zeek/src/Expr.cc
Tim Wojtulewicz a159d075cf Add Trigger manager for managing triggers created by things like 'when' statements
- Adds new trigger namespace
- Adds trigger::Manager class as a new IOSource for keeping track of triggers and integrating them into the loop. Previously the loop relied on the event manager Drain() method to process all triggers on every loop, but now that the loop actively waits for events to occur, triggers would not fire when they needed to. Adding them as part of the loop ensures they're checked.
2020-01-31 10:13:09 -07:00

5247 lines
103 KiB
C++

// See the file "COPYING" in the main distribution directory for copyright.
#include "zeek-config.h"
#include "Expr.h"
#include "Event.h"
#include "Frame.h"
#include "Func.h"
#include "RE.h"
#include "Scope.h"
#include "Stmt.h"
#include "EventRegistry.h"
#include "Net.h"
#include "Traverse.h"
#include "Trigger.h"
#include "IPAddr.h"
#include "digest.h"
#include "broker/Data.h"
const char* expr_name(BroExprTag t)
{
static const char* expr_names[int(NUM_EXPRS)] = {
"name", "const",
"(*)",
"++", "--", "!", "~", "+", "-",
"+", "-", "+=", "-=", "*", "/", "%",
"&", "|", "^",
"&&", "||",
"<", "<=", "==", "!=", ">=", ">", "?:", "ref",
"=", "[]", "$", "?$", "[=]",
"table()", "set()", "vector()",
"$=", "in", "<<>>",
"()", "function()", "event", "schedule",
"coerce", "record_coerce", "table_coerce",
"sizeof", "flatten", "cast", "is", "[:]="
};
if ( int(t) >= NUM_EXPRS )
{
static char errbuf[512];
// This isn't quite right - we return a static buffer,
// so multiple calls to expr_name() could lead to confusion
// by overwriting the buffer. But oh well.
snprintf(errbuf, sizeof(errbuf),
"%d: not an expression tag", int(t));
return errbuf;
}
return expr_names[int(t)];
}
Expr::Expr(BroExprTag arg_tag)
{
tag = arg_tag;
type = 0;
paren = 0;
SetLocationInfo(&start_location, &end_location);
}
Expr::~Expr()
{
Unref(type);
}
int Expr::CanAdd() const
{
return 0;
}
int Expr::CanDel() const
{
return 0;
}
void Expr::Add(Frame* /* f */)
{
Internal("Expr::Delete called");
}
void Expr::Delete(Frame* /* f */)
{
Internal("Expr::Delete called");
}
Expr* Expr::MakeLvalue()
{
if ( ! IsError() )
ExprError("can't be assigned to");
return this;
}
void Expr::EvalIntoAggregate(const BroType* /* t */, Val* /* aggr */,
Frame* /* f */) const
{
Internal("Expr::EvalIntoAggregate called");
}
void Expr::Assign(Frame* /* f */, Val* /* v */)
{
Internal("Expr::Assign called");
}
BroType* Expr::InitType() const
{
return type->Ref();
}
int Expr::IsRecordElement(TypeDecl* /* td */) const
{
return 0;
}
int Expr::IsPure() const
{
return 1;
}
Val* Expr::InitVal(const BroType* t, Val* aggr) const
{
if ( aggr )
{
Error("bad initializer");
return 0;
}
if ( IsError() )
return 0;
return check_and_promote(Eval(0), t, 1);
}
void Expr::SetError(const char* msg)
{
Error(msg);
SetError();
}
void Expr::Describe(ODesc* d) const
{
if ( IsParen() && ! d->IsBinary() )
d->Add("(");
if ( d->IsPortable() || d->IsBinary() )
AddTag(d);
ExprDescribe(d);
if ( IsParen() && ! d->IsBinary() )
d->Add(")");
}
void Expr::AddTag(ODesc* d) const
{
if ( d->IsBinary() )
d->Add(int(Tag()));
else
d->AddSP(expr_name(Tag()));
}
void Expr::Canonicize()
{
}
void Expr::SetType(BroType* t)
{
if ( ! type || type->Tag() != TYPE_ERROR )
{
Unref(type);
type = t;
}
else
Unref(t);
}
void Expr::ExprError(const char msg[])
{
Error(msg);
SetError();
}
void Expr::RuntimeError(const std::string& msg) const
{
reporter->ExprRuntimeError(this, "%s", msg.data());
}
void Expr::RuntimeErrorWithCallStack(const std::string& msg) const
{
auto rcs = render_call_stack();
if ( rcs.empty() )
reporter->ExprRuntimeError(this, "%s", msg.data());
else
{
ODesc d;
d.SetShort();
Describe(&d);
reporter->RuntimeError(GetLocationInfo(), "%s, expression: %s, call stack: %s",
msg.data(), d.Description(), rcs.data());
}
}
NameExpr::NameExpr(ID* arg_id, bool const_init) : Expr(EXPR_NAME)
{
id = arg_id;
in_const_init = const_init;
if ( id->AsType() )
SetType(new TypeType(id->AsType()));
else
SetType(id->Type()->Ref());
EventHandler* h = event_registry->Lookup(id->Name());
if ( h )
h->SetUsed();
}
NameExpr::~NameExpr()
{
Unref(id);
}
Val* NameExpr::Eval(Frame* f) const
{
Val* v;
if ( id->AsType() )
return new Val(id->AsType(), true);
if ( id->IsGlobal() )
v = id->ID_Val();
else if ( f )
v = f->GetElement(id);
else
// No frame - evaluating for Simplify() purposes
return 0;
if ( v )
return v->Ref();
else
{
RuntimeError("value used but not set");
return 0;
}
}
Expr* NameExpr::MakeLvalue()
{
if ( id->AsType() )
ExprError("Type name is not an lvalue");
if ( id->IsConst() && ! in_const_init )
ExprError("const is not a modifiable lvalue");
if ( id->IsOption() && ! in_const_init )
ExprError("option is not a modifiable lvalue");
return new RefExpr(this);
}
void NameExpr::Assign(Frame* f, Val* v)
{
if ( id->IsGlobal() )
id->SetVal(v);
else
f->SetElement(id, v);
}
int NameExpr::IsPure() const
{
return id->IsConst();
}
TraversalCode NameExpr::Traverse(TraversalCallback* cb) const
{
TraversalCode tc = cb->PreExpr(this);
HANDLE_TC_EXPR_PRE(tc);
tc = id->Traverse(cb);
HANDLE_TC_EXPR_PRE(tc);
tc = cb->PostExpr(this);
HANDLE_TC_EXPR_POST(tc);
}
void NameExpr::ExprDescribe(ODesc* d) const
{
if ( d->IsReadable() )
d->Add(id->Name());
else
{
if ( d->IsPortable() )
d->Add(id->Name());
else
d->AddCS(id->Name());
}
}
ConstExpr::ConstExpr(Val* arg_val) : Expr(EXPR_CONST)
{
val = arg_val;
if ( val->Type()->Tag() == TYPE_LIST && val->AsListVal()->Length() == 1 )
{
val = val->AsListVal()->Index(0);
val->Ref();
Unref(arg_val);
}
SetType(val->Type()->Ref());
}
ConstExpr::~ConstExpr()
{
Unref(val);
}
void ConstExpr::ExprDescribe(ODesc* d) const
{
val->Describe(d);
}
Val* ConstExpr::Eval(Frame* /* f */) const
{
return Value()->Ref();
}
TraversalCode ConstExpr::Traverse(TraversalCallback* cb) const
{
TraversalCode tc = cb->PreExpr(this);
HANDLE_TC_EXPR_PRE(tc);
tc = cb->PostExpr(this);
HANDLE_TC_EXPR_POST(tc);
}
UnaryExpr::UnaryExpr(BroExprTag arg_tag, Expr* arg_op) : Expr(arg_tag)
{
op = arg_op;
if ( op->IsError() )
SetError();
}
UnaryExpr::~UnaryExpr()
{
Unref(op);
}
Val* UnaryExpr::Eval(Frame* f) const
{
if ( IsError() )
return 0;
Val* v = op->Eval(f);
if ( ! v )
return 0;
if ( is_vector(v) && Tag() != EXPR_IS && Tag() != EXPR_CAST )
{
VectorVal* v_op = v->AsVectorVal();
VectorType* out_t;
if ( Type()->Tag() == TYPE_ANY )
out_t = v->Type()->AsVectorType();
else
out_t = Type()->AsVectorType();
VectorVal* result = new VectorVal(out_t);
for ( unsigned int i = 0; i < v_op->Size(); ++i )
{
Val* v_i = v_op->Lookup(i);
result->Assign(i, v_i ? Fold(v_i) : 0);
}
Unref(v);
return result;
}
else
{
Val* result = Fold(v);
Unref(v);
return result;
}
}
int UnaryExpr::IsPure() const
{
return op->IsPure();
}
TraversalCode UnaryExpr::Traverse(TraversalCallback* cb) const
{
TraversalCode tc = cb->PreExpr(this);
HANDLE_TC_EXPR_PRE(tc);
tc = op->Traverse(cb);
HANDLE_TC_EXPR_PRE(tc);
tc = cb->PostExpr(this);
HANDLE_TC_EXPR_POST(tc);
}
Val* UnaryExpr::Fold(Val* v) const
{
return v->Ref();
}
void UnaryExpr::ExprDescribe(ODesc* d) const
{
bool is_coerce =
Tag() == EXPR_ARITH_COERCE || Tag() == EXPR_RECORD_COERCE ||
Tag() == EXPR_TABLE_COERCE;
if ( d->IsReadable() )
{
if ( is_coerce )
d->Add("(coerce ");
else if ( Tag() == EXPR_FLATTEN )
d->Add("flatten ");
else if ( Tag() != EXPR_REF )
d->Add(expr_name(Tag()));
}
op->Describe(d);
if ( d->IsReadable() && is_coerce )
{
d->Add(" to ");
Type()->Describe(d);
d->Add(")");
}
}
BinaryExpr::~BinaryExpr()
{
Unref(op1);
Unref(op2);
}
Val* BinaryExpr::Eval(Frame* f) const
{
if ( IsError() )
return 0;
Val* v1 = op1->Eval(f);
if ( ! v1 )
return 0;
Val* v2 = op2->Eval(f);
if ( ! v2 )
{
Unref(v1);
return 0;
}
Val* result = 0;
int is_vec1 = is_vector(v1);
int is_vec2 = is_vector(v2);
if ( is_vec1 && is_vec2 )
{ // fold pairs of elements
VectorVal* v_op1 = v1->AsVectorVal();
VectorVal* v_op2 = v2->AsVectorVal();
if ( v_op1->Size() != v_op2->Size() )
{
RuntimeError("vector operands are of different sizes");
return 0;
}
VectorVal* v_result = new VectorVal(Type()->AsVectorType());
for ( unsigned int i = 0; i < v_op1->Size(); ++i )
{
if ( v_op1->Lookup(i) && v_op2->Lookup(i) )
v_result->Assign(i,
Fold(v_op1->Lookup(i),
v_op2->Lookup(i)));
else
v_result->Assign(i, 0);
// SetError("undefined element in vector operation");
}
Unref(v1);
Unref(v2);
return v_result;
}
if ( IsVector(Type()->Tag()) && (is_vec1 || is_vec2) )
{ // fold vector against scalar
VectorVal* vv = (is_vec1 ? v1 : v2)->AsVectorVal();
VectorVal* v_result = new VectorVal(Type()->AsVectorType());
for ( unsigned int i = 0; i < vv->Size(); ++i )
{
Val* vv_i = vv->Lookup(i);
if ( vv_i )
v_result->Assign(i,
is_vec1 ?
Fold(vv_i, v2) : Fold(v1, vv_i));
else
v_result->Assign(i, 0);
// SetError("Undefined element in vector operation");
}
Unref(v1);
Unref(v2);
return v_result;
}
// scalar op scalar
result = Fold(v1, v2);
Unref(v1);
Unref(v2);
return result;
}
int BinaryExpr::IsPure() const
{
return op1->IsPure() && op2->IsPure();
}
TraversalCode BinaryExpr::Traverse(TraversalCallback* cb) const
{
TraversalCode tc = cb->PreExpr(this);
HANDLE_TC_EXPR_PRE(tc);
tc = op1->Traverse(cb);
HANDLE_TC_EXPR_PRE(tc);
tc = op2->Traverse(cb);
HANDLE_TC_EXPR_PRE(tc);
tc = cb->PostExpr(this);
HANDLE_TC_EXPR_POST(tc);
}
void BinaryExpr::ExprDescribe(ODesc* d) const
{
op1->Describe(d);
d->SP();
if ( d->IsReadable() )
d->AddSP(expr_name(Tag()));
op2->Describe(d);
}
Val* BinaryExpr::Fold(Val* v1, Val* v2) const
{
InternalTypeTag it = v1->Type()->InternalType();
if ( it == TYPE_INTERNAL_STRING )
return StringFold(v1, v2);
if ( v1->Type()->Tag() == TYPE_PATTERN )
return PatternFold(v1, v2);
if ( v1->Type()->IsSet() )
return SetFold(v1, v2);
if ( it == TYPE_INTERNAL_ADDR )
return AddrFold(v1, v2);
if ( it == TYPE_INTERNAL_SUBNET )
return SubNetFold(v1, v2);
bro_int_t i1 = 0, i2 = 0, i3 = 0;
bro_uint_t u1 = 0, u2 = 0, u3 = 0;
double d1 = 0.0, d2 = 0.0, d3 = 0.0;
int is_integral = 0;
int is_unsigned = 0;
if ( it == TYPE_INTERNAL_INT )
{
i1 = v1->InternalInt();
i2 = v2->InternalInt();
++is_integral;
}
else if ( it == TYPE_INTERNAL_UNSIGNED )
{
u1 = v1->InternalUnsigned();
u2 = v2->InternalUnsigned();
++is_unsigned;
}
else if ( it == TYPE_INTERNAL_DOUBLE )
{
d1 = v1->InternalDouble();
d2 = v2->InternalDouble();
}
else
RuntimeErrorWithCallStack("bad type in BinaryExpr::Fold");
switch ( tag ) {
#define DO_INT_FOLD(op) \
if ( is_integral ) \
i3 = i1 op i2; \
else if ( is_unsigned ) \
u3 = u1 op u2; \
else \
RuntimeErrorWithCallStack("bad type in BinaryExpr::Fold");
#define DO_UINT_FOLD(op) \
if ( is_unsigned ) \
u3 = u1 op u2; \
else \
RuntimeErrorWithCallStack("bad type in BinaryExpr::Fold");
#define DO_FOLD(op) \
if ( is_integral ) \
i3 = i1 op i2; \
else if ( is_unsigned ) \
u3 = u1 op u2; \
else \
d3 = d1 op d2;
#define DO_INT_VAL_FOLD(op) \
if ( is_integral ) \
i3 = i1 op i2; \
else if ( is_unsigned ) \
i3 = u1 op u2; \
else \
i3 = d1 op d2;
case EXPR_ADD: DO_FOLD(+); break;
case EXPR_ADD_TO: DO_FOLD(+); break;
case EXPR_SUB: DO_FOLD(-); break;
case EXPR_REMOVE_FROM: DO_FOLD(-); break;
case EXPR_TIMES: DO_FOLD(*); break;
case EXPR_DIVIDE:
{
if ( is_integral )
{
if ( i2 == 0 )
RuntimeError("division by zero");
i3 = i1 / i2;
}
else if ( is_unsigned )
{
if ( u2 == 0 )
RuntimeError("division by zero");
u3 = u1 / u2;
}
else
{
if ( d2 == 0 )
RuntimeError("division by zero");
d3 = d1 / d2;
}
}
break;
case EXPR_MOD:
{
if ( is_integral )
{
if ( i2 == 0 )
RuntimeError("modulo by zero");
i3 = i1 % i2;
}
else if ( is_unsigned )
{
if ( u2 == 0 )
RuntimeError("modulo by zero");
u3 = u1 % u2;
}
else
RuntimeErrorWithCallStack("bad type in BinaryExpr::Fold");
}
break;
case EXPR_AND: DO_UINT_FOLD(&); break;
case EXPR_OR: DO_UINT_FOLD(|); break;
case EXPR_XOR: DO_UINT_FOLD(^); break;
case EXPR_AND_AND: DO_INT_FOLD(&&); break;
case EXPR_OR_OR: DO_INT_FOLD(||); break;
case EXPR_LT: DO_INT_VAL_FOLD(<); break;
case EXPR_LE: DO_INT_VAL_FOLD(<=); break;
case EXPR_EQ: DO_INT_VAL_FOLD(==); break;
case EXPR_NE: DO_INT_VAL_FOLD(!=); break;
case EXPR_GE: DO_INT_VAL_FOLD(>=); break;
case EXPR_GT: DO_INT_VAL_FOLD(>); break;
default:
BadTag("BinaryExpr::Fold", expr_name(tag));
}
BroType* ret_type = type;
if ( IsVector(ret_type->Tag()) )
ret_type = ret_type->YieldType();
if ( ret_type->Tag() == TYPE_INTERVAL )
return new IntervalVal(d3, 1.0);
else if ( ret_type->InternalType() == TYPE_INTERNAL_DOUBLE )
return new Val(d3, ret_type->Tag());
else if ( ret_type->InternalType() == TYPE_INTERNAL_UNSIGNED )
return val_mgr->GetCount(u3);
else if ( ret_type->Tag() == TYPE_BOOL )
return val_mgr->GetBool(i3);
else
return val_mgr->GetInt(i3);
}
Val* BinaryExpr::StringFold(Val* v1, Val* v2) const
{
const BroString* s1 = v1->AsString();
const BroString* s2 = v2->AsString();
int result = 0;
switch ( tag ) {
#undef DO_FOLD
#define DO_FOLD(sense) { result = Bstr_cmp(s1, s2) sense 0; break; }
case EXPR_LT: DO_FOLD(<)
case EXPR_LE: DO_FOLD(<=)
case EXPR_EQ: DO_FOLD(==)
case EXPR_NE: DO_FOLD(!=)
case EXPR_GE: DO_FOLD(>=)
case EXPR_GT: DO_FOLD(>)
case EXPR_ADD:
case EXPR_ADD_TO:
{
vector<const BroString*> strings;
strings.push_back(s1);
strings.push_back(s2);
return new StringVal(concatenate(strings));
}
default:
BadTag("BinaryExpr::StringFold", expr_name(tag));
}
return val_mgr->GetBool(result);
}
Val* BinaryExpr::PatternFold(Val* v1, Val* v2) const
{
const RE_Matcher* re1 = v1->AsPattern();
const RE_Matcher* re2 = v2->AsPattern();
if ( tag != EXPR_AND && tag != EXPR_OR )
BadTag("BinaryExpr::PatternFold");
RE_Matcher* res = tag == EXPR_AND ?
RE_Matcher_conjunction(re1, re2) :
RE_Matcher_disjunction(re1, re2);
return new PatternVal(res);
}
Val* BinaryExpr::SetFold(Val* v1, Val* v2) const
{
TableVal* tv1 = v1->AsTableVal();
TableVal* tv2 = v2->AsTableVal();
TableVal* result;
bool res = false;
switch ( tag ) {
case EXPR_AND:
return tv1->Intersect(tv2);
case EXPR_OR:
result = v1->Clone()->AsTableVal();
if ( ! tv2->AddTo(result, false, false) )
reporter->InternalError("set union failed to type check");
return result;
case EXPR_SUB:
result = v1->Clone()->AsTableVal();
if ( ! tv2->RemoveFrom(result) )
reporter->InternalError("set difference failed to type check");
return result;
case EXPR_EQ:
res = tv1->EqualTo(tv2);
break;
case EXPR_NE:
res = ! tv1->EqualTo(tv2);
break;
case EXPR_LT:
res = tv1->IsSubsetOf(tv2) && tv1->Size() < tv2->Size();
break;
case EXPR_LE:
res = tv1->IsSubsetOf(tv2);
break;
case EXPR_GE:
case EXPR_GT:
// These should't happen due to canonicalization.
reporter->InternalError("confusion over canonicalization in set comparison");
break;
default:
BadTag("BinaryExpr::SetFold", expr_name(tag));
return 0;
}
return val_mgr->GetBool(res);
}
Val* BinaryExpr::AddrFold(Val* v1, Val* v2) const
{
IPAddr a1 = v1->AsAddr();
IPAddr a2 = v2->AsAddr();
int result = 0;
switch ( tag ) {
case EXPR_LT:
result = a1 < a2;
break;
case EXPR_LE:
result = a1 < a2 || a1 == a2;
break;
case EXPR_EQ:
result = a1 == a2;
break;
case EXPR_NE:
result = a1 != a2;
break;
case EXPR_GE:
result = ! ( a1 < a2 );
break;
case EXPR_GT:
result = ( ! ( a1 < a2 ) ) && ( a1 != a2 );
break;
default:
BadTag("BinaryExpr::AddrFold", expr_name(tag));
}
return val_mgr->GetBool(result);
}
Val* BinaryExpr::SubNetFold(Val* v1, Val* v2) const
{
const IPPrefix& n1 = v1->AsSubNet();
const IPPrefix& n2 = v2->AsSubNet();
bool result = ( n1 == n2 ) ? true : false;
if ( tag == EXPR_NE )
result = ! result;
return val_mgr->GetBool(result);
}
void BinaryExpr::SwapOps()
{
// We could check here whether the operator is commutative.
Expr* t = op1;
op1 = op2;
op2 = t;
}
void BinaryExpr::PromoteOps(TypeTag t)
{
TypeTag bt1 = op1->Type()->Tag();
TypeTag bt2 = op2->Type()->Tag();
bool is_vec1 = IsVector(bt1);
bool is_vec2 = IsVector(bt2);
if ( is_vec1 )
bt1 = op1->Type()->AsVectorType()->YieldType()->Tag();
if ( is_vec2 )
bt2 = op2->Type()->AsVectorType()->YieldType()->Tag();
if ( (is_vec1 || is_vec2) && ! (is_vec1 && is_vec2) )
reporter->Warning("mixing vector and scalar operands is deprecated");
if ( bt1 != t )
op1 = new ArithCoerceExpr(op1, t);
if ( bt2 != t )
op2 = new ArithCoerceExpr(op2, t);
}
void BinaryExpr::PromoteType(TypeTag t, bool is_vector)
{
PromoteOps(t);
SetType(is_vector ? new VectorType(base_type(t)) : base_type(t));
}
CloneExpr::CloneExpr(Expr* arg_op) : UnaryExpr(EXPR_CLONE, arg_op)
{
if ( IsError() )
return;
BroType* t = op->Type();
SetType(t->Ref());
}
Val* CloneExpr::Eval(Frame* f) const
{
if ( IsError() )
return 0;
Val* v = op->Eval(f);
if ( ! v )
return 0;
Val* result = Fold(v);
Unref(v);
return result;
}
Val* CloneExpr::Fold(Val* v) const
{
return v->Clone();
}
IncrExpr::IncrExpr(BroExprTag arg_tag, Expr* arg_op)
: UnaryExpr(arg_tag, arg_op->MakeLvalue())
{
if ( IsError() )
return;
BroType* t = op->Type();
if ( IsVector(t->Tag()) )
{
if ( ! IsIntegral(t->AsVectorType()->YieldType()->Tag()) )
ExprError("vector elements must be integral for increment operator");
else
{
reporter->Warning("increment/decrement operations for vectors deprecated");
SetType(t->Ref());
}
}
else
{
if ( ! IsIntegral(t->Tag()) )
ExprError("requires an integral operand");
else
SetType(t->Ref());
}
}
Val* IncrExpr::DoSingleEval(Frame* f, Val* v) const
{
bro_int_t k = v->CoerceToInt();
if ( Tag() == EXPR_INCR )
++k;
else
{
--k;
if ( k < 0 &&
v->Type()->InternalType() == TYPE_INTERNAL_UNSIGNED )
RuntimeError("count underflow");
}
BroType* ret_type = Type();
if ( IsVector(ret_type->Tag()) )
ret_type = Type()->YieldType();
if ( ret_type->Tag() == TYPE_INT )
return val_mgr->GetInt(k);
else
return val_mgr->GetCount(k);
}
Val* IncrExpr::Eval(Frame* f) const
{
Val* v = op->Eval(f);
if ( ! v )
return 0;
if ( is_vector(v) )
{
VectorVal* v_vec = v->AsVectorVal();
for ( unsigned int i = 0; i < v_vec->Size(); ++i )
{
Val* elt = v_vec->Lookup(i);
if ( elt )
{
Val* new_elt = DoSingleEval(f, elt);
v_vec->Assign(i, new_elt);
}
else
v_vec->Assign(i, 0);
}
op->Assign(f, v_vec);
}
else
{
Val* old_v = v;
op->Assign(f, v = DoSingleEval(f, old_v));
Unref(old_v);
}
return v->Ref();
}
int IncrExpr::IsPure() const
{
return 0;
}
ComplementExpr::ComplementExpr(Expr* arg_op) : UnaryExpr(EXPR_COMPLEMENT, arg_op)
{
if ( IsError() )
return;
BroType* t = op->Type();
TypeTag bt = t->Tag();
if ( bt != TYPE_COUNT )
ExprError("requires \"count\" operand");
else
SetType(base_type(TYPE_COUNT));
}
Val* ComplementExpr::Fold(Val* v) const
{
return val_mgr->GetCount(~ v->InternalUnsigned());
}
NotExpr::NotExpr(Expr* arg_op) : UnaryExpr(EXPR_NOT, arg_op)
{
if ( IsError() )
return;
BroType* t = op->Type();
TypeTag bt = t->Tag();
if ( ! IsIntegral(bt) && bt != TYPE_BOOL )
ExprError("requires an integral or boolean operand");
else
SetType(base_type(TYPE_BOOL));
}
Val* NotExpr::Fold(Val* v) const
{
return val_mgr->GetBool(! v->InternalInt());
}
PosExpr::PosExpr(Expr* arg_op) : UnaryExpr(EXPR_POSITIVE, arg_op)
{
if ( IsError() )
return;
BroType* t = op->Type();
if ( IsVector(t->Tag()) )
t = t->AsVectorType()->YieldType();
TypeTag bt = t->Tag();
BroType* base_result_type = 0;
if ( IsIntegral(bt) )
// Promote count and counter to int.
base_result_type = base_type(TYPE_INT);
else if ( bt == TYPE_INTERVAL || bt == TYPE_DOUBLE )
base_result_type = t->Ref();
else
ExprError("requires an integral or double operand");
if ( is_vector(op) )
SetType(new VectorType(base_result_type));
else
SetType(base_result_type);
}
Val* PosExpr::Fold(Val* v) const
{
TypeTag t = v->Type()->Tag();
if ( t == TYPE_DOUBLE || t == TYPE_INTERVAL || t == TYPE_INT )
return v->Ref();
else
return val_mgr->GetInt(v->CoerceToInt());
}
NegExpr::NegExpr(Expr* arg_op) : UnaryExpr(EXPR_NEGATE, arg_op)
{
if ( IsError() )
return;
BroType* t = op->Type();
if ( IsVector(t->Tag()) )
t = t->AsVectorType()->YieldType();
TypeTag bt = t->Tag();
BroType* base_result_type = 0;
if ( IsIntegral(bt) )
// Promote count and counter to int.
base_result_type = base_type(TYPE_INT);
else if ( bt == TYPE_INTERVAL || bt == TYPE_DOUBLE )
base_result_type = t->Ref();
else
ExprError("requires an integral or double operand");
if ( is_vector(op) )
SetType(new VectorType(base_result_type));
else
SetType(base_result_type);
}
Val* NegExpr::Fold(Val* v) const
{
if ( v->Type()->Tag() == TYPE_DOUBLE )
return new Val(- v->InternalDouble(), v->Type()->Tag());
else if ( v->Type()->Tag() == TYPE_INTERVAL )
return new IntervalVal(- v->InternalDouble(), 1.0);
else
return val_mgr->GetInt(- v->CoerceToInt());
}
SizeExpr::SizeExpr(Expr* arg_op) : UnaryExpr(EXPR_SIZE, arg_op)
{
if ( IsError() )
return;
if ( op->Type()->InternalType() == TYPE_INTERNAL_DOUBLE )
SetType(base_type(TYPE_DOUBLE));
else
SetType(base_type(TYPE_COUNT));
}
Val* SizeExpr::Eval(Frame* f) const
{
Val* v = op->Eval(f);
if ( ! v )
return 0;
Val* result = Fold(v);
Unref(v);
return result;
}
Val* SizeExpr::Fold(Val* v) const
{
return v->SizeVal();
}
AddExpr::AddExpr(Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(EXPR_ADD, arg_op1, arg_op2)
{
if ( IsError() )
return;
TypeTag bt1 = op1->Type()->Tag();
if ( IsVector(bt1) )
bt1 = op1->Type()->AsVectorType()->YieldType()->Tag();
TypeTag bt2 = op2->Type()->Tag();
if ( IsVector(bt2) )
bt2 = op2->Type()->AsVectorType()->YieldType()->Tag();
BroType* base_result_type = 0;
if ( bt1 == TYPE_TIME && bt2 == TYPE_INTERVAL )
base_result_type = base_type(bt1);
else if ( bt2 == TYPE_TIME && bt1 == TYPE_INTERVAL )
base_result_type = base_type(bt2);
else if ( bt1 == TYPE_INTERVAL && bt2 == TYPE_INTERVAL )
base_result_type = base_type(bt1);
else if ( BothArithmetic(bt1, bt2) )
PromoteType(max_type(bt1, bt2), is_vector(op1) || is_vector(op2));
else if ( BothString(bt1, bt2) )
base_result_type = base_type(bt1);
else
ExprError("requires arithmetic operands");
if ( base_result_type )
{
if ( is_vector(op1) || is_vector(op2) )
SetType(new VectorType(base_result_type));
else
SetType(base_result_type);
}
}
void AddExpr::Canonicize()
{
if ( expr_greater(op2, op1) ||
(op1->Type()->Tag() == TYPE_INTERVAL &&
op2->Type()->Tag() == TYPE_TIME) ||
(op2->IsConst() && ! is_vector(op2->ExprVal()) && ! op1->IsConst()))
SwapOps();
}
AddToExpr::AddToExpr(Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(EXPR_ADD_TO,
is_vector(arg_op1) ? arg_op1 : arg_op1->MakeLvalue(), arg_op2)
{
if ( IsError() )
return;
TypeTag bt1 = op1->Type()->Tag();
TypeTag bt2 = op2->Type()->Tag();
if ( BothArithmetic(bt1, bt2) )
PromoteType(max_type(bt1, bt2), is_vector(op1) || is_vector(op2));
else if ( BothString(bt1, bt2) )
SetType(base_type(bt1));
else if ( BothInterval(bt1, bt2) )
SetType(base_type(bt1));
else if ( IsVector(bt1) )
{
bt1 = op1->Type()->AsVectorType()->YieldType()->Tag();
if ( IsArithmetic(bt1) )
{
if ( IsArithmetic(bt2) )
{
if ( bt2 != bt1 )
op2 = new ArithCoerceExpr(op2, bt1);
SetType(op1->Type()->Ref());
}
else
ExprError("appending non-arithmetic to arithmetic vector");
}
else if ( bt1 != bt2 && bt1 != TYPE_ANY )
ExprError(fmt("incompatible vector append: %s and %s",
type_name(bt1), type_name(bt2)));
else
SetType(op1->Type()->Ref());
}
else
ExprError("requires two arithmetic or two string operands");
}
Val* AddToExpr::Eval(Frame* f) const
{
Val* v1 = op1->Eval(f);
if ( ! v1 )
return 0;
Val* v2 = op2->Eval(f);
if ( ! v2 )
{
Unref(v1);
return 0;
}
if ( is_vector(v1) )
{
VectorVal* vv = v1->AsVectorVal();
if ( ! vv->Assign(vv->Size(), v2) )
RuntimeError("type-checking failed in vector append");
return v1;
}
Val* result = Fold(v1, v2);
Unref(v1);
Unref(v2);
if ( result )
{
op1->Assign(f, result);
return result->Ref();
}
else
return 0;
}
SubExpr::SubExpr(Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(EXPR_SUB, arg_op1, arg_op2)
{
if ( IsError() )
return;
const BroType* t1 = op1->Type();
const BroType* t2 = op2->Type();
TypeTag bt1 = t1->Tag();
if ( IsVector(bt1) )
bt1 = t1->AsVectorType()->YieldType()->Tag();
TypeTag bt2 = t2->Tag();
if ( IsVector(bt2) )
bt2 = t2->AsVectorType()->YieldType()->Tag();
BroType* base_result_type = 0;
if ( bt1 == TYPE_TIME && bt2 == TYPE_INTERVAL )
base_result_type = base_type(bt1);
else if ( bt1 == TYPE_TIME && bt2 == TYPE_TIME )
SetType(base_type(TYPE_INTERVAL));
else if ( bt1 == TYPE_INTERVAL && bt2 == TYPE_INTERVAL )
base_result_type = base_type(bt1);
else if ( t1->IsSet() && t2->IsSet() )
{
if ( same_type(t1, t2) )
SetType(op1->Type()->Ref());
else
ExprError("incompatible \"set\" operands");
}
else if ( BothArithmetic(bt1, bt2) )
PromoteType(max_type(bt1, bt2), is_vector(op1) || is_vector(op2));
else
ExprError("requires arithmetic operands");
if ( base_result_type )
{
if ( is_vector(op1) || is_vector(op2) )
SetType(new VectorType(base_result_type));
else
SetType(base_result_type);
}
}
RemoveFromExpr::RemoveFromExpr(Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(EXPR_REMOVE_FROM, arg_op1->MakeLvalue(), arg_op2)
{
if ( IsError() )
return;
TypeTag bt1 = op1->Type()->Tag();
TypeTag bt2 = op2->Type()->Tag();
if ( BothArithmetic(bt1, bt2) )
PromoteType(max_type(bt1, bt2), is_vector(op1) || is_vector(op2));
else if ( BothInterval(bt1, bt2) )
SetType(base_type(bt1));
else
ExprError("requires two arithmetic operands");
}
Val* RemoveFromExpr::Eval(Frame* f) const
{
Val* v1 = op1->Eval(f);
if ( ! v1 )
return 0;
Val* v2 = op2->Eval(f);
if ( ! v2 )
{
Unref(v1);
return 0;
}
Val* result = Fold(v1, v2);
Unref(v1);
Unref(v2);
if ( result )
{
op1->Assign(f, result);
return result->Ref();
}
else
return 0;
}
TimesExpr::TimesExpr(Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(EXPR_TIMES, arg_op1, arg_op2)
{
if ( IsError() )
return;
Canonicize();
TypeTag bt1 = op1->Type()->Tag();
if ( IsVector(bt1) )
bt1 = op1->Type()->AsVectorType()->YieldType()->Tag();
TypeTag bt2 = op2->Type()->Tag();
if ( IsVector(bt2) )
bt2 = op2->Type()->AsVectorType()->YieldType()->Tag();
if ( bt1 == TYPE_INTERVAL || bt2 == TYPE_INTERVAL )
{
if ( IsArithmetic(bt1) || IsArithmetic(bt2) )
PromoteType(TYPE_INTERVAL, is_vector(op1) || is_vector(op2) );
else
ExprError("multiplication with interval requires arithmetic operand");
}
else if ( BothArithmetic(bt1, bt2) )
PromoteType(max_type(bt1, bt2), is_vector(op1) || is_vector(op2));
else
ExprError("requires arithmetic operands");
}
void TimesExpr::Canonicize()
{
if ( expr_greater(op2, op1) || op2->Type()->Tag() == TYPE_INTERVAL ||
(op2->IsConst() && ! is_vector(op2->ExprVal()) && ! op1->IsConst()) )
SwapOps();
}
DivideExpr::DivideExpr(Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(EXPR_DIVIDE, arg_op1, arg_op2)
{
if ( IsError() )
return;
TypeTag bt1 = op1->Type()->Tag();
if ( IsVector(bt1) )
bt1 = op1->Type()->AsVectorType()->YieldType()->Tag();
TypeTag bt2 = op2->Type()->Tag();
if ( IsVector(bt2) )
bt2 = op2->Type()->AsVectorType()->YieldType()->Tag();
if ( bt1 == TYPE_INTERVAL || bt2 == TYPE_INTERVAL )
{
if ( IsArithmetic(bt1) || IsArithmetic(bt2) )
PromoteType(TYPE_INTERVAL, is_vector(op1) || is_vector(op2));
else if ( bt1 == TYPE_INTERVAL && bt2 == TYPE_INTERVAL )
{
if ( is_vector(op1) || is_vector(op2) )
SetType(new VectorType(base_type(TYPE_DOUBLE)));
else
SetType(base_type(TYPE_DOUBLE));
}
else
ExprError("division of interval requires arithmetic operand");
}
else if ( BothArithmetic(bt1, bt2) )
PromoteType(max_type(bt1, bt2), is_vector(op1) || is_vector(op2));
else if ( bt1 == TYPE_ADDR && ! is_vector(op2) &&
(bt2 == TYPE_COUNT || bt2 == TYPE_INT) )
SetType(base_type(TYPE_SUBNET));
else
ExprError("requires arithmetic operands");
}
Val* DivideExpr::AddrFold(Val* v1, Val* v2) const
{
uint32_t mask;
if ( v2->Type()->Tag() == TYPE_COUNT )
mask = static_cast<uint32_t>(v2->InternalUnsigned());
else
mask = static_cast<uint32_t>(v2->InternalInt());
auto& a = v1->AsAddr();
if ( a.GetFamily() == IPv4 )
{
if ( mask > 32 )
RuntimeError(fmt("bad IPv4 subnet prefix length: %" PRIu32, mask));
}
else
{
if ( mask > 128 )
RuntimeError(fmt("bad IPv6 subnet prefix length: %" PRIu32, mask));
}
return new SubNetVal(a, mask);
}
ModExpr::ModExpr(Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(EXPR_MOD, arg_op1, arg_op2)
{
if ( IsError() )
return;
TypeTag bt1 = op1->Type()->Tag();
if ( IsVector(bt1) )
bt1 = op1->Type()->AsVectorType()->YieldType()->Tag();
TypeTag bt2 = op2->Type()->Tag();
if ( IsVector(bt2) )
bt2 = op2->Type()->AsVectorType()->YieldType()->Tag();
if ( BothIntegral(bt1, bt2) )
PromoteType(max_type(bt1, bt2), is_vector(op1) || is_vector(op2));
else
ExprError("requires integral operands");
}
BoolExpr::BoolExpr(BroExprTag arg_tag, Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(arg_tag, arg_op1, arg_op2)
{
if ( IsError() )
return;
TypeTag bt1 = op1->Type()->Tag();
if ( IsVector(bt1) )
bt1 = op1->Type()->AsVectorType()->YieldType()->Tag();
TypeTag bt2 = op2->Type()->Tag();
if ( IsVector(bt2) )
bt2 = op2->Type()->AsVectorType()->YieldType()->Tag();
if ( BothBool(bt1, bt2) )
{
if ( is_vector(op1) || is_vector(op2) )
{
if ( ! (is_vector(op1) && is_vector(op2)) )
reporter->Warning("mixing vector and scalar operands is deprecated");
SetType(new VectorType(base_type(TYPE_BOOL)));
}
else
SetType(base_type(TYPE_BOOL));
}
else
ExprError("requires boolean operands");
}
Val* BoolExpr::DoSingleEval(Frame* f, Val* v1, Expr* op2) const
{
if ( ! v1 )
return 0;
if ( tag == EXPR_AND_AND )
{
if ( v1->IsZero() )
return v1;
else
{
Unref(v1);
return op2->Eval(f);
}
}
else
{
if ( v1->IsZero() )
{
Unref(v1);
return op2->Eval(f);
}
else
return v1;
}
}
Val* BoolExpr::Eval(Frame* f) const
{
if ( IsError() )
return 0;
Val* v1 = op1->Eval(f);
if ( ! v1 )
return 0;
int is_vec1 = is_vector(op1);
int is_vec2 = is_vector(op2);
// Handle scalar op scalar
if ( ! is_vec1 && ! is_vec2 )
return DoSingleEval(f, v1, op2);
// Handle scalar op vector or vector op scalar
// We can't short-circuit everything since we need to eval
// a vector in order to find out its length.
if ( ! (is_vec1 && is_vec2) )
{ // Only one is a vector.
Val* scalar_v = 0;
VectorVal* vector_v = 0;
if ( is_vec1 )
{
scalar_v = op2->Eval(f);
vector_v = v1->AsVectorVal();
}
else
{
scalar_v = v1;
vector_v = op2->Eval(f)->AsVectorVal();
}
if ( ! scalar_v || ! vector_v )
return 0;
VectorVal* result = 0;
// It's either an EXPR_AND_AND or an EXPR_OR_OR.
bool is_and = (tag == EXPR_AND_AND);
if ( scalar_v->IsZero() == is_and )
{
result = new VectorVal(Type()->AsVectorType());
result->Resize(vector_v->Size());
result->AssignRepeat(0, result->Size(),
scalar_v);
}
else
result = vector_v->Ref()->AsVectorVal();
Unref(scalar_v);
Unref(vector_v);
return result;
}
// Only case remaining: both are vectors.
Val* v2 = op2->Eval(f);
if ( ! v2 )
return 0;
VectorVal* vec_v1 = v1->AsVectorVal();
VectorVal* vec_v2 = v2->AsVectorVal();
if ( vec_v1->Size() != vec_v2->Size() )
{
RuntimeError("vector operands have different sizes");
return 0;
}
VectorVal* result = new VectorVal(Type()->AsVectorType());
result->Resize(vec_v1->Size());
for ( unsigned int i = 0; i < vec_v1->Size(); ++i )
{
Val* op1 = vec_v1->Lookup(i);
Val* op2 = vec_v2->Lookup(i);
if ( op1 && op2 )
{
bool local_result = (tag == EXPR_AND_AND) ?
(! op1->IsZero() && ! op2->IsZero()) :
(! op1->IsZero() || ! op2->IsZero());
result->Assign(i, val_mgr->GetBool(local_result));
}
else
result->Assign(i, 0);
}
Unref(v1);
Unref(v2);
return result;
}
BitExpr::BitExpr(BroExprTag arg_tag, Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(arg_tag, arg_op1, arg_op2)
{
if ( IsError() )
return;
const BroType* t1 = op1->Type();
const BroType* t2 = op2->Type();
TypeTag bt1 = t1->Tag();
if ( IsVector(bt1) )
bt1 = t1->AsVectorType()->YieldType()->Tag();
TypeTag bt2 = t2->Tag();
if ( IsVector(bt2) )
bt2 = t2->AsVectorType()->YieldType()->Tag();
if ( (bt1 == TYPE_COUNT || bt1 == TYPE_COUNTER) &&
(bt2 == TYPE_COUNT || bt2 == TYPE_COUNTER) )
{
if ( bt1 == TYPE_COUNTER && bt2 == TYPE_COUNTER )
ExprError("cannot apply a bitwise operator to two \"counter\" operands");
else if ( is_vector(op1) || is_vector(op2) )
SetType(new VectorType(base_type(TYPE_COUNT)));
else
SetType(base_type(TYPE_COUNT));
}
else if ( bt1 == TYPE_PATTERN )
{
if ( bt2 != TYPE_PATTERN )
ExprError("cannot mix pattern and non-pattern operands");
else if ( tag == EXPR_XOR )
ExprError("'^' operator does not apply to patterns");
else
SetType(base_type(TYPE_PATTERN));
}
else if ( t1->IsSet() && t2->IsSet() )
{
if ( same_type(t1, t2) )
SetType(op1->Type()->Ref());
else
ExprError("incompatible \"set\" operands");
}
else
ExprError("requires \"count\" or compatible \"set\" operands");
}
EqExpr::EqExpr(BroExprTag arg_tag, Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(arg_tag, arg_op1, arg_op2)
{
if ( IsError() )
return;
Canonicize();
const BroType* t1 = op1->Type();
const BroType* t2 = op2->Type();
TypeTag bt1 = t1->Tag();
if ( IsVector(bt1) )
bt1 = t1->AsVectorType()->YieldType()->Tag();
TypeTag bt2 = t2->Tag();
if ( IsVector(bt2) )
bt2 = t2->AsVectorType()->YieldType()->Tag();
if ( is_vector(op1) || is_vector(op2) )
SetType(new VectorType(base_type(TYPE_BOOL)));
else
SetType(base_type(TYPE_BOOL));
if ( BothArithmetic(bt1, bt2) )
PromoteOps(max_type(bt1, bt2));
else if ( EitherArithmetic(bt1, bt2) &&
// Allow comparisons with zero.
((bt1 == TYPE_TIME && op2->IsZero()) ||
(bt2 == TYPE_TIME && op1->IsZero())) )
PromoteOps(TYPE_TIME);
else if ( bt1 == bt2 )
{
switch ( bt1 ) {
case TYPE_BOOL:
case TYPE_TIME:
case TYPE_INTERVAL:
case TYPE_STRING:
case TYPE_PORT:
case TYPE_ADDR:
case TYPE_SUBNET:
case TYPE_ERROR:
break;
case TYPE_ENUM:
if ( ! same_type(t1, t2) )
ExprError("illegal enum comparison");
break;
case TYPE_TABLE:
if ( t1->IsSet() && t2->IsSet() )
{
if ( ! same_type(t1, t2) )
ExprError("incompatible sets in comparison");
break;
}
// FALL THROUGH
default:
ExprError("illegal comparison");
}
}
else if ( bt1 == TYPE_PATTERN && bt2 == TYPE_STRING )
;
else
ExprError("type clash in comparison");
}
void EqExpr::Canonicize()
{
if ( op2->Type()->Tag() == TYPE_PATTERN )
SwapOps();
else if ( op1->Type()->Tag() == TYPE_PATTERN )
;
else if ( expr_greater(op2, op1) )
SwapOps();
}
Val* EqExpr::Fold(Val* v1, Val* v2) const
{
if ( op1->Type()->Tag() == TYPE_PATTERN )
{
RE_Matcher* re = v1->AsPattern();
const BroString* s = v2->AsString();
if ( tag == EXPR_EQ )
return val_mgr->GetBool(re->MatchExactly(s));
else
return val_mgr->GetBool(! re->MatchExactly(s));
}
else
return BinaryExpr::Fold(v1, v2);
}
RelExpr::RelExpr(BroExprTag arg_tag, Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(arg_tag, arg_op1, arg_op2)
{
if ( IsError() )
return;
Canonicize();
const BroType* t1 = op1->Type();
const BroType* t2 = op2->Type();
TypeTag bt1 = t1->Tag();
if ( IsVector(bt1) )
bt1 = t1->AsVectorType()->YieldType()->Tag();
TypeTag bt2 = t2->Tag();
if ( IsVector(bt2) )
bt2 = t2->AsVectorType()->YieldType()->Tag();
if ( is_vector(op1) || is_vector(op2) )
SetType(new VectorType(base_type(TYPE_BOOL)));
else
SetType(base_type(TYPE_BOOL));
if ( BothArithmetic(bt1, bt2) )
PromoteOps(max_type(bt1, bt2));
else if ( t1->IsSet() && t2->IsSet() )
{
if ( ! same_type(t1, t2) )
ExprError("incompatible sets in comparison");
}
else if ( bt1 != bt2 )
ExprError("operands must be of the same type");
else if ( bt1 != TYPE_TIME && bt1 != TYPE_INTERVAL &&
bt1 != TYPE_PORT && bt1 != TYPE_ADDR &&
bt1 != TYPE_STRING )
ExprError("illegal comparison");
}
void RelExpr::Canonicize()
{
if ( tag == EXPR_GT )
{
SwapOps();
tag = EXPR_LT;
}
else if ( tag == EXPR_GE )
{
SwapOps();
tag = EXPR_LE;
}
}
CondExpr::CondExpr(Expr* arg_op1, Expr* arg_op2, Expr* arg_op3)
: Expr(EXPR_COND)
{
op1 = arg_op1;
op2 = arg_op2;
op3 = arg_op3;
TypeTag bt1 = op1->Type()->Tag();
if ( IsVector(bt1) )
bt1 = op1->Type()->AsVectorType()->YieldType()->Tag();
if ( op1->IsError() || op2->IsError() || op3->IsError() )
SetError();
else if ( bt1 != TYPE_BOOL )
ExprError("requires boolean conditional");
else
{
TypeTag bt2 = op2->Type()->Tag();
if ( is_vector(op2) )
bt2 = op2->Type()->AsVectorType()->YieldType()->Tag();
TypeTag bt3 = op3->Type()->Tag();
if ( IsVector(bt3) )
bt3 = op3->Type()->AsVectorType()->YieldType()->Tag();
if ( is_vector(op1) && ! (is_vector(op2) && is_vector(op3)) )
{
ExprError("vector conditional requires vector alternatives");
return;
}
if ( BothArithmetic(bt2, bt3) )
{
TypeTag t = max_type(bt2, bt3);
if ( bt2 != t )
op2 = new ArithCoerceExpr(op2, t);
if ( bt3 != t )
op3 = new ArithCoerceExpr(op3, t);
if ( is_vector(op2) )
SetType(new VectorType(base_type(t)));
else
SetType(base_type(t));
}
else if ( bt2 != bt3 )
ExprError("operands must be of the same type");
else
{
if ( IsRecord(bt2) && IsRecord(bt3) &&
! same_type(op2->Type(), op3->Type()) )
ExprError("operands must be of the same type");
else
SetType(op2->Type()->Ref());
}
}
}
CondExpr::~CondExpr()
{
Unref(op1);
Unref(op2);
Unref(op3);
}
Val* CondExpr::Eval(Frame* f) const
{
if ( ! is_vector(op1) )
{ // scalar is easy
Val* v = op1->Eval(f);
int false_eval = v->IsZero();
Unref(v);
return (false_eval ? op3 : op2)->Eval(f);
}
// Vector case: no mixed scalar/vector cases allowed
Val* v1 = op1->Eval(f);
if ( ! v1 )
return 0;
Val* v2 = op2->Eval(f);
if ( ! v2 )
return 0;
Val* v3 = op3->Eval(f);
if ( ! v3 )
return 0;
VectorVal* cond = v1->AsVectorVal();
VectorVal* a = v2->AsVectorVal();
VectorVal* b = v3->AsVectorVal();
if ( cond->Size() != a->Size() || a->Size() != b->Size() )
{
RuntimeError("vectors in conditional expression have different sizes");
return 0;
}
VectorVal* result = new VectorVal(Type()->AsVectorType());
result->Resize(cond->Size());
for ( unsigned int i = 0; i < cond->Size(); ++i )
{
Val* local_cond = cond->Lookup(i);
if ( local_cond )
result->Assign(i,
local_cond->IsZero() ?
b->Lookup(i) : a->Lookup(i));
else
result->Assign(i, 0);
}
return result;
}
int CondExpr::IsPure() const
{
return op1->IsPure() && op2->IsPure() && op3->IsPure();
}
TraversalCode CondExpr::Traverse(TraversalCallback* cb) const
{
TraversalCode tc = cb->PreExpr(this);
HANDLE_TC_EXPR_PRE(tc);
tc = op1->Traverse(cb);
HANDLE_TC_EXPR_PRE(tc);
tc = op2->Traverse(cb);
HANDLE_TC_EXPR_PRE(tc);
tc = op3->Traverse(cb);
HANDLE_TC_EXPR_PRE(tc);
tc = cb->PostExpr(this);
HANDLE_TC_EXPR_POST(tc);
}
void CondExpr::ExprDescribe(ODesc* d) const
{
op1->Describe(d);
d->AddSP(" ?");
op2->Describe(d);
d->AddSP(" :");
op3->Describe(d);
}
RefExpr::RefExpr(Expr* arg_op) : UnaryExpr(EXPR_REF, arg_op)
{
if ( IsError() )
return;
if ( ! ::is_assignable(op->Type()) )
ExprError("illegal assignment target");
else
SetType(op->Type()->Ref());
}
Expr* RefExpr::MakeLvalue()
{
return this;
}
void RefExpr::Assign(Frame* f, Val* v)
{
op->Assign(f, v);
}
AssignExpr::AssignExpr(Expr* arg_op1, Expr* arg_op2, int arg_is_init,
Val* arg_val, attr_list* arg_attrs)
: BinaryExpr(EXPR_ASSIGN,
arg_is_init ? arg_op1 : arg_op1->MakeLvalue(), arg_op2)
{
val = 0;
is_init = arg_is_init;
if ( IsError() )
return;
SetType(arg_val ? arg_val->Type()->Ref() : op1->Type()->Ref());
if ( is_init )
{
SetLocationInfo(arg_op1->GetLocationInfo(),
arg_op2->GetLocationInfo());
return;
}
// We discard the status from TypeCheck since it has already
// generated error messages.
(void) TypeCheck(arg_attrs);
val = arg_val ? arg_val->Ref() : 0;
SetLocationInfo(arg_op1->GetLocationInfo(), arg_op2->GetLocationInfo());
}
bool AssignExpr::TypeCheck(attr_list* attrs)
{
TypeTag bt1 = op1->Type()->Tag();
TypeTag bt2 = op2->Type()->Tag();
if ( bt1 == TYPE_LIST && bt2 == TYPE_ANY )
// This is ok because we cannot explicitly declare lists on
// the script level.
return true;
if ( ((bt1 == TYPE_ENUM) ^ (bt2 == TYPE_ENUM)) )
{
ExprError("can't convert to/from enumerated type");
return false;
}
if ( IsArithmetic(bt1) )
return TypeCheckArithmetics(bt1, bt2);
if ( bt1 == TYPE_TIME && IsArithmetic(bt2) && op2->IsZero() )
{ // Allow assignments to zero as a special case.
op2 = new ArithCoerceExpr(op2, bt1);
return true;
}
if ( bt1 == TYPE_TABLE && bt2 == bt1 &&
op2->Type()->AsTableType()->IsUnspecifiedTable() )
{
op2 = new TableCoerceExpr(op2, op1->Type()->AsTableType());
return true;
}
if ( bt1 == TYPE_TABLE && op2->Tag() == EXPR_LIST )
{
attr_list* attr_copy = 0;
if ( attrs )
{
attr_copy = new attr_list(attrs->length());
std::copy(attrs->begin(), attrs->end(), std::back_inserter(*attr_copy));
}
bool empty_list_assignment = (op2->AsListExpr()->Exprs().length() == 0);
if ( op1->Type()->IsSet() )
op2 = new SetConstructorExpr(op2->AsListExpr(), attr_copy);
else
op2 = new TableConstructorExpr(op2->AsListExpr(), attr_copy);
if ( ! empty_list_assignment && ! same_type(op1->Type(), op2->Type()) )
{
if ( op1->Type()->IsSet() )
ExprError("set type mismatch in assignment");
else
ExprError("table type mismatch in assignment");
return false;
}
return true;
}
if ( bt1 == TYPE_VECTOR )
{
if ( bt2 == bt1 && op2->Type()->AsVectorType()->IsUnspecifiedVector() )
{
op2 = new VectorCoerceExpr(op2, op1->Type()->AsVectorType());
return true;
}
if ( op2->Tag() == EXPR_LIST )
{
op2 = new VectorConstructorExpr(op2->AsListExpr(), op1->Type());
return true;
}
}
if ( op1->Type()->Tag() == TYPE_RECORD &&
op2->Type()->Tag() == TYPE_RECORD )
{
if ( same_type(op1->Type(), op2->Type()) )
{
RecordType* rt1 = op1->Type()->AsRecordType();
RecordType* rt2 = op2->Type()->AsRecordType();
// Make sure the attributes match as well.
for ( int i = 0; i < rt1->NumFields(); ++i )
{
const TypeDecl* td1 = rt1->FieldDecl(i);
const TypeDecl* td2 = rt2->FieldDecl(i);
if ( same_attrs(td1->attrs, td2->attrs) )
// Everything matches.
return true;
}
}
// Need to coerce.
op2 = new RecordCoerceExpr(op2, op1->Type()->AsRecordType());
return true;
}
if ( ! same_type(op1->Type(), op2->Type()) )
{
if ( bt1 == TYPE_TABLE && bt2 == TYPE_TABLE )
{
if ( op2->Tag() == EXPR_SET_CONSTRUCTOR )
{
// Some elements in constructor list must not match, see if
// we can create a new constructor now that the expected type
// of LHS is known and let it do coercions where possible.
SetConstructorExpr* sce = dynamic_cast<SetConstructorExpr*>(op2);
if ( ! sce )
{
ExprError("Failed typecast to SetConstructorExpr");
return false;
}
ListExpr* ctor_list = dynamic_cast<ListExpr*>(sce->Op());
if ( ! ctor_list )
{
ExprError("Failed typecast to ListExpr");
return false;
}
attr_list* attr_copy = 0;
if ( sce->Attrs() )
{
attr_list* a = sce->Attrs()->Attrs();
attrs = new attr_list(a->length());
std::copy(a->begin(), a->end(), std::back_inserter(*attrs));
}
int errors_before = reporter->Errors();
op2 = new SetConstructorExpr(ctor_list, attr_copy, op1->Type());
int errors_after = reporter->Errors();
if ( errors_after > errors_before )
{
ExprError("type clash in assignment");
return false;
}
return true;
}
}
ExprError("type clash in assignment");
return false;
}
return true;
}
bool AssignExpr::TypeCheckArithmetics(TypeTag bt1, TypeTag bt2)
{
if ( ! IsArithmetic(bt2) )
{
char err[512];
snprintf(err, sizeof(err),
"assignment of non-arithmetic value to arithmetic (%s/%s)",
type_name(bt1), type_name(bt2));
ExprError(err);
return false;
}
if ( bt1 == TYPE_DOUBLE )
{
PromoteOps(TYPE_DOUBLE);
return true;
}
if ( bt2 == TYPE_DOUBLE )
{
Warn("dangerous assignment of double to integral");
op2 = new ArithCoerceExpr(op2, bt1);
bt2 = op2->Type()->Tag();
}
if ( bt1 == TYPE_INT )
PromoteOps(TYPE_INT);
else
{
if ( bt2 == TYPE_INT )
{
Warn("dangerous assignment of integer to count");
op2 = new ArithCoerceExpr(op2, bt1);
bt2 = op2->Type()->Tag();
}
// Assignment of count to counter or vice
// versa is allowed, and requires no
// coercion.
}
return true;
}
Val* AssignExpr::Eval(Frame* f) const
{
if ( is_init )
{
RuntimeError("illegal assignment in initialization");
return 0;
}
Val* v = op2->Eval(f);
if ( v )
{
op1->Assign(f, v);
return val ? val->Ref() : v->Ref();
}
else
return 0;
}
BroType* AssignExpr::InitType() const
{
if ( op1->Tag() != EXPR_LIST )
{
Error("bad initializer");
return 0;
}
BroType* tl = op1->Type();
if ( tl->Tag() != TYPE_LIST )
Internal("inconsistent list expr in AssignExpr::InitType");
return new TableType(tl->Ref()->AsTypeList(), op2->Type()->Ref());
}
void AssignExpr::EvalIntoAggregate(const BroType* t, Val* aggr, Frame* f) const
{
if ( IsError() )
return;
TypeDecl td(0, 0);
if ( IsRecordElement(&td) )
{
if ( t->Tag() != TYPE_RECORD )
{
RuntimeError("not a record initializer");
return;
}
const RecordType* rt = t->AsRecordType();
int field = rt->FieldOffset(td.id);
if ( field < 0 )
{
RuntimeError("no such field");
return;
}
RecordVal* aggr_r = aggr->AsRecordVal();
Val* v = op2->Eval(f);
if ( v )
aggr_r->Assign(field, v);
return;
}
if ( op1->Tag() != EXPR_LIST )
RuntimeError("bad table insertion");
TableVal* tv = aggr->AsTableVal();
Val* index = op1->Eval(f);
Val* v = check_and_promote(op2->Eval(f), t->YieldType(), 1);
if ( ! index || ! v )
return;
if ( ! tv->Assign(index, v) )
RuntimeError("type clash in table assignment");
Unref(index);
}
Val* AssignExpr::InitVal(const BroType* t, Val* aggr) const
{
if ( ! aggr )
{
Error("assignment in initialization");
return 0;
}
if ( IsError() )
return 0;
TypeDecl td(0, 0);
if ( IsRecordElement(&td) )
{
if ( t->Tag() != TYPE_RECORD )
{
Error("not a record initializer", t);
return 0;
}
const RecordType* rt = t->AsRecordType();
int field = rt->FieldOffset(td.id);
if ( field < 0 )
{
Error("no such field");
return 0;
}
if ( aggr->Type()->Tag() != TYPE_RECORD )
Internal("bad aggregate in AssignExpr::InitVal");
RecordVal* aggr_r = aggr->AsRecordVal();
Val* v = op2->InitVal(rt->FieldType(td.id), 0);
if ( ! v )
return 0;
aggr_r->Assign(field, v);
return v;
}
else if ( op1->Tag() == EXPR_LIST )
{
if ( t->Tag() != TYPE_TABLE )
{
Error("not a table initialization", t);
return 0;
}
if ( aggr->Type()->Tag() != TYPE_TABLE )
Internal("bad aggregate in AssignExpr::InitVal");
TableVal* tv = aggr->AsTableVal();
const TableType* tt = tv->Type()->AsTableType();
const BroType* yt = tv->Type()->YieldType();
Val* index = op1->InitVal(tt->Indices(), 0);
Val* v = op2->InitVal(yt, 0);
if ( ! index || ! v )
return 0;
if ( ! tv->ExpandAndInit(index, v) )
{
Unref(index);
Unref(tv);
return 0;
}
Unref(index);
return tv;
}
else
{
Error("illegal initializer");
return 0;
}
}
int AssignExpr::IsRecordElement(TypeDecl* td) const
{
if ( op1->Tag() == EXPR_NAME )
{
if ( td )
{
const NameExpr* n = (const NameExpr*) op1;
td->type = op2->Type()->Ref();
td->id = copy_string(n->Id()->Name());
}
return 1;
}
else
return 0;
}
int AssignExpr::IsPure() const
{
return 0;
}
IndexSliceAssignExpr::IndexSliceAssignExpr(Expr* op1, Expr* op2, int is_init)
: AssignExpr(op1, op2, is_init)
{
}
Val* IndexSliceAssignExpr::Eval(Frame* f) const
{
if ( is_init )
{
RuntimeError("illegal assignment in initialization");
return 0;
}
Val* v = op2->Eval(f);
if ( v )
{
op1->Assign(f, v);
Unref(v);
}
return 0;
}
IndexExpr::IndexExpr(Expr* arg_op1, ListExpr* arg_op2, bool arg_is_slice)
: BinaryExpr(EXPR_INDEX, arg_op1, arg_op2), is_slice(arg_is_slice)
{
if ( IsError() )
return;
if ( is_slice )
{
if ( ! IsString(op1->Type()->Tag()) && ! IsVector(op1->Type()->Tag()) )
ExprError("slice notation indexing only supported for strings and vectors currently");
}
else if ( IsString(op1->Type()->Tag()) )
{
if ( arg_op2->Exprs().length() != 1 )
ExprError("invalid string index expression");
}
if ( IsError() )
return;
int match_type = op1->Type()->MatchesIndex(arg_op2);
if ( match_type == DOES_NOT_MATCH_INDEX )
{
std::string error_msg =
fmt("expression with type '%s' is not a type that can be indexed",
type_name(op1->Type()->Tag()));
SetError(error_msg.data());
}
else if ( ! op1->Type()->YieldType() )
{
if ( IsString(op1->Type()->Tag()) && match_type == MATCHES_INDEX_SCALAR )
SetType(base_type(TYPE_STRING));
else
// It's a set - so indexing it yields void. We don't
// directly generate an error message, though, since this
// expression might be part of an add/delete statement,
// rather than yielding a value.
SetType(base_type(TYPE_VOID));
}
else if ( match_type == MATCHES_INDEX_SCALAR )
SetType(op1->Type()->YieldType()->Ref());
else if ( match_type == MATCHES_INDEX_VECTOR )
SetType(new VectorType(op1->Type()->YieldType()->Ref()));
else
ExprError("Unknown MatchesIndex() return value");
}
int IndexExpr::CanAdd() const
{
if ( IsError() )
return 1; // avoid cascading the error report
// "add" only allowed if our type is "set".
return op1->Type()->IsSet();
}
int IndexExpr::CanDel() const
{
if ( IsError() )
return 1; // avoid cascading the error report
return op1->Type()->Tag() == TYPE_TABLE;
}
void IndexExpr::Add(Frame* f)
{
if ( IsError() )
return;
Val* v1 = op1->Eval(f);
if ( ! v1 )
return;
Val* v2 = op2->Eval(f);
if ( ! v2 )
{
Unref(v1);
return;
}
v1->AsTableVal()->Assign(v2, 0);
Unref(v1);
Unref(v2);
}
void IndexExpr::Delete(Frame* f)
{
if ( IsError() )
return;
Val* v1 = op1->Eval(f);
if ( ! v1 )
return;
Val* v2 = op2->Eval(f);
if ( ! v2 )
{
Unref(v1);
return;
}
Unref(v1->AsTableVal()->Delete(v2));
Unref(v1);
Unref(v2);
}
Expr* IndexExpr::MakeLvalue()
{
if ( IsString(op1->Type()->Tag()) )
ExprError("cannot assign to string index expression");
return new RefExpr(this);
}
Val* IndexExpr::Eval(Frame* f) const
{
Val* v1 = op1->Eval(f);
if ( ! v1 )
return 0;
Val* v2 = op2->Eval(f);
if ( ! v2 )
{
Unref(v1);
return 0;
}
Val* result;
Val* indv = v2->AsListVal()->Index(0);
if ( is_vector(indv) )
{
VectorVal* v_v1 = v1->AsVectorVal();
VectorVal* v_v2 = indv->AsVectorVal();
VectorVal* v_result = new VectorVal(Type()->AsVectorType());
result = v_result;
// Booleans select each element (or not).
if ( IsBool(v_v2->Type()->YieldType()->Tag()) )
{
if ( v_v1->Size() != v_v2->Size() )
{
RuntimeError("size mismatch, boolean index and vector");
Unref(v_result);
return 0;
}
for ( unsigned int i = 0; i < v_v2->Size(); ++i )
{
if ( v_v2->Lookup(i)->AsBool() )
v_result->Assign(v_result->Size() + 1, v_v1->Lookup(i));
}
}
else
{ // The elements are indices.
// ### Should handle negative indices here like
// S does, i.e., by excluding those elements.
// Probably only do this if *all* are negative.
v_result->Resize(v_v2->Size());
for ( unsigned int i = 0; i < v_v2->Size(); ++i )
v_result->Assign(i, v_v1->Lookup(v_v2->Lookup(i)->CoerceToInt()));
}
}
else
result = Fold(v1, v2);
Unref(v1);
Unref(v2);
return result;
}
static int get_slice_index(int idx, int len)
{
if ( abs(idx) > len )
idx = idx > 0 ? len : 0; // Clamp maximum positive/negative indices.
else if ( idx < 0 )
idx += len; // Map to a positive index.
return idx;
}
Val* IndexExpr::Fold(Val* v1, Val* v2) const
{
if ( IsError() )
return 0;
Val* v = 0;
switch ( v1->Type()->Tag() ) {
case TYPE_VECTOR:
{
VectorVal* vect = v1->AsVectorVal();
const ListVal* lv = v2->AsListVal();
if ( lv->Length() == 1 )
v = vect->Lookup(v2);
else
{
int len = vect->Size();
VectorVal* result = new VectorVal(vect->Type()->AsVectorType());
bro_int_t first = get_slice_index(lv->Index(0)->CoerceToInt(), len);
bro_int_t last = get_slice_index(lv->Index(1)->CoerceToInt(), len);
int sub_length = last - first;
if ( sub_length >= 0 )
{
result->Resize(sub_length);
for ( int idx = first; idx < last; idx++ )
result->Assign(idx - first, vect->Lookup(idx)->Ref());
}
return result;
}
}
break;
case TYPE_TABLE:
v = v1->AsTableVal()->Lookup(v2); // Then, we jump into the TableVal here.
break;
case TYPE_STRING:
{
const ListVal* lv = v2->AsListVal();
const BroString* s = v1->AsString();
int len = s->Len();
BroString* substring = 0;
if ( lv->Length() == 1 )
{
bro_int_t idx = lv->Index(0)->AsInt();
if ( idx < 0 )
idx += len;
// Out-of-range index will return null pointer.
substring = s->GetSubstring(idx, 1);
}
else
{
bro_int_t first = get_slice_index(lv->Index(0)->AsInt(), len);
bro_int_t last = get_slice_index(lv->Index(1)->AsInt(), len);
int substring_len = last - first;
if ( substring_len < 0 )
substring = 0;
else
substring = s->GetSubstring(first, substring_len);
}
return new StringVal(substring ? substring : new BroString(""));
}
default:
RuntimeError("type cannot be indexed");
break;
}
if ( v )
return v->Ref();
RuntimeError("no such index");
return 0;
}
void IndexExpr::Assign(Frame* f, Val* v)
{
if ( IsError() )
return;
Val* v1 = op1->Eval(f);
if ( ! v1 )
return;
Val* v2 = op2->Eval(f);
if ( ! v1 || ! v2 )
{
Unref(v1);
Unref(v2);
return;
}
switch ( v1->Type()->Tag() ) {
case TYPE_VECTOR:
{
const ListVal* lv = v2->AsListVal();
VectorVal* v1_vect = v1->AsVectorVal();
if ( lv->Length() > 1 )
{
auto len = v1_vect->Size();
bro_int_t first = get_slice_index(lv->Index(0)->CoerceToInt(), len);
bro_int_t last = get_slice_index(lv->Index(1)->CoerceToInt(), len);
// Remove the elements from the vector within the slice
for ( auto idx = first; idx < last; idx++ )
v1_vect->Remove(first);
// Insert the new elements starting at the first position
VectorVal* v_vect = v->AsVectorVal();
for ( auto idx = 0u; idx < v_vect->Size(); idx++, first++ )
v1_vect->Insert(first, v_vect->Lookup(idx)->Ref());
}
else if ( ! v1_vect->Assign(v2, v) )
{
if ( v )
{
ODesc d;
v->Describe(&d);
auto vt = v->Type();
auto vtt = vt->Tag();
std::string tn = vtt == TYPE_RECORD ? vt->GetName() : type_name(vtt);
RuntimeErrorWithCallStack(fmt(
"vector index assignment failed for invalid type '%s', value: %s",
tn.data(), d.Description()));
}
else
RuntimeErrorWithCallStack("assignment failed with null value");
}
break;
}
case TYPE_TABLE:
if ( ! v1->AsTableVal()->Assign(v2, v) )
{
if ( v )
{
ODesc d;
v->Describe(&d);
auto vt = v->Type();
auto vtt = vt->Tag();
std::string tn = vtt == TYPE_RECORD ? vt->GetName() : type_name(vtt);
RuntimeErrorWithCallStack(fmt(
"table index assignment failed for invalid type '%s', value: %s",
tn.data(), d.Description()));
}
else
RuntimeErrorWithCallStack("assignment failed with null value");
}
break;
case TYPE_STRING:
RuntimeErrorWithCallStack("assignment via string index accessor not allowed");
break;
default:
RuntimeErrorWithCallStack("bad index expression type in assignment");
break;
}
Unref(v1);
Unref(v2);
}
void IndexExpr::ExprDescribe(ODesc* d) const
{
op1->Describe(d);
if ( d->IsReadable() )
d->Add("[");
op2->Describe(d);
if ( d->IsReadable() )
d->Add("]");
}
TraversalCode IndexExpr::Traverse(TraversalCallback* cb) const
{
TraversalCode tc = cb->PreExpr(this);
HANDLE_TC_EXPR_PRE(tc);
tc = op1->Traverse(cb);
HANDLE_TC_EXPR_PRE(tc);
tc = op2->Traverse(cb);
HANDLE_TC_EXPR_PRE(tc);
tc = cb->PostExpr(this);
HANDLE_TC_EXPR_POST(tc);
}
FieldExpr::FieldExpr(Expr* arg_op, const char* arg_field_name)
: UnaryExpr(EXPR_FIELD, arg_op)
{
field_name = copy_string(arg_field_name);
td = 0;
field = 0;
if ( IsError() )
return;
if ( ! IsRecord(op->Type()->Tag()) )
ExprError("not a record");
else
{
RecordType* rt = op->Type()->AsRecordType();
field = rt->FieldOffset(field_name);
if ( field < 0 )
ExprError("no such field in record");
else
{
SetType(rt->FieldType(field)->Ref());
td = rt->FieldDecl(field);
if ( rt->IsFieldDeprecated(field) )
reporter->Warning("%s", rt->GetFieldDeprecationWarning(field, false).c_str());
}
}
}
FieldExpr::~FieldExpr()
{
delete [] field_name;
}
Expr* FieldExpr::MakeLvalue()
{
return new RefExpr(this);
}
int FieldExpr::CanDel() const
{
return td->FindAttr(ATTR_DEFAULT) || td->FindAttr(ATTR_OPTIONAL);
}
void FieldExpr::Assign(Frame* f, Val* v)
{
if ( IsError() )
return;
Val* op_v = op->Eval(f);
if ( op_v )
{
RecordVal* r = op_v->AsRecordVal();
r->Assign(field, v);
Unref(r);
}
}
void FieldExpr::Delete(Frame* f)
{
Assign(f, 0);
}
Val* FieldExpr::Fold(Val* v) const
{
Val* result = v->AsRecordVal()->Lookup(field);
if ( result )
return result->Ref();
// Check for &default.
const Attr* def_attr = td ? td->FindAttr(ATTR_DEFAULT) : 0;
if ( def_attr )
return def_attr->AttrExpr()->Eval(0);
else
{
RuntimeError("field value missing");
assert(false);
return 0; // Will never get here, but compiler can't tell.
}
}
void FieldExpr::ExprDescribe(ODesc* d) const
{
op->Describe(d);
if ( d->IsReadable() )
d->Add("$");
if ( IsError() )
d->Add("<error>");
else if ( d->IsReadable() )
d->Add(field_name);
else
d->Add(field);
}
HasFieldExpr::HasFieldExpr(Expr* arg_op, const char* arg_field_name)
: UnaryExpr(EXPR_HAS_FIELD, arg_op)
{
field_name = arg_field_name;
field = 0;
if ( IsError() )
return;
if ( ! IsRecord(op->Type()->Tag()) )
ExprError("not a record");
else
{
RecordType* rt = op->Type()->AsRecordType();
field = rt->FieldOffset(field_name);
if ( field < 0 )
ExprError("no such field in record");
else if ( rt->IsFieldDeprecated(field) )
reporter->Warning("%s", rt->GetFieldDeprecationWarning(field, true).c_str());
SetType(base_type(TYPE_BOOL));
}
}
HasFieldExpr::~HasFieldExpr()
{
delete field_name;
}
Val* HasFieldExpr::Fold(Val* v) const
{
RecordVal* rec_to_look_at;
rec_to_look_at = v->AsRecordVal();
if ( ! rec_to_look_at )
return val_mgr->GetBool(0);
RecordVal* r = rec_to_look_at->Ref()->AsRecordVal();
Val* ret = val_mgr->GetBool(r->Lookup(field) != 0);
Unref(r);
return ret;
}
void HasFieldExpr::ExprDescribe(ODesc* d) const
{
op->Describe(d);
if ( d->IsReadable() )
d->Add("?$");
if ( IsError() )
d->Add("<error>");
else if ( d->IsReadable() )
d->Add(field_name);
else
d->Add(field);
}
RecordConstructorExpr::RecordConstructorExpr(ListExpr* constructor_list)
: UnaryExpr(EXPR_RECORD_CONSTRUCTOR, constructor_list)
{
if ( IsError() )
return;
// Spin through the list, which should be comprised only of
// record-field-assign expressions, and build up a
// record type to associate with this constructor.
const expr_list& exprs = constructor_list->Exprs();
type_decl_list* record_types = new type_decl_list(exprs.length());
for ( const auto& e : exprs )
{
if ( e->Tag() != EXPR_FIELD_ASSIGN )
{
Error("bad type in record constructor", e);
SetError();
continue;
}
FieldAssignExpr* field = (FieldAssignExpr*) e;
BroType* field_type = field->Type()->Ref();
char* field_name = copy_string(field->FieldName());
record_types->push_back(new TypeDecl(field_type, field_name));
}
SetType(new RecordType(record_types));
}
RecordConstructorExpr::~RecordConstructorExpr()
{
}
Val* RecordConstructorExpr::InitVal(const BroType* t, Val* aggr) const
{
Val* v = Eval(0);
if ( v )
{
RecordVal* rv = v->AsRecordVal();
RecordVal* ar = rv->CoerceTo(t->AsRecordType(), aggr);
if ( ar )
{
Unref(rv);
return ar;
}
}
Error("bad record initializer");
return 0;
}
Val* RecordConstructorExpr::Fold(Val* v) const
{
ListVal* lv = v->AsListVal();
RecordType* rt = type->AsRecordType();
if ( lv->Length() != rt->NumFields() )
RuntimeErrorWithCallStack("inconsistency evaluating record constructor");
RecordVal* rv = new RecordVal(rt);
for ( int i = 0; i < lv->Length(); ++i )
rv->Assign(i, lv->Index(i)->Ref());
return rv;
}
void RecordConstructorExpr::ExprDescribe(ODesc* d) const
{
d->Add("[");
op->Describe(d);
d->Add("]");
}
TableConstructorExpr::TableConstructorExpr(ListExpr* constructor_list,
attr_list* arg_attrs, BroType* arg_type)
: UnaryExpr(EXPR_TABLE_CONSTRUCTOR, constructor_list)
{
attrs = 0;
if ( IsError() )
return;
if ( arg_type )
{
if ( ! arg_type->IsTable() )
{
Error("bad table constructor type", arg_type);
SetError();
return;
}
SetType(arg_type->Ref());
}
else
{
if ( constructor_list->Exprs().length() == 0 )
SetType(new TableType(new TypeList(base_type(TYPE_ANY)), 0));
else
{
SetType(init_type(constructor_list));
if ( ! type )
SetError();
else if ( type->Tag() != TYPE_TABLE ||
type->AsTableType()->IsSet() )
SetError("values in table(...) constructor do not specify a table");
}
}
attrs = arg_attrs ? new Attributes(arg_attrs, type, false, false) : 0;
type_list* indices = type->AsTableType()->Indices()->Types();
const expr_list& cle = constructor_list->Exprs();
// check and promote all index expressions in ctor list
for ( const auto& expr : cle )
{
if ( expr->Tag() != EXPR_ASSIGN )
continue;
Expr* idx_expr = expr->AsAssignExpr()->Op1();
if ( idx_expr->Tag() != EXPR_LIST )
continue;
expr_list& idx_exprs = idx_expr->AsListExpr()->Exprs();
if ( idx_exprs.length() != indices->length() )
continue;
loop_over_list(idx_exprs, j)
{
Expr* idx = idx_exprs[j];
if ( check_and_promote_expr(idx, (*indices)[j]) )
{
if ( idx != idx_exprs[j] )
idx_exprs.replace(j, idx);
continue;
}
ExprError("inconsistent types in table constructor");
}
}
}
Val* TableConstructorExpr::Eval(Frame* f) const
{
if ( IsError() )
return 0;
Val* aggr = new TableVal(Type()->AsTableType(), attrs);
const expr_list& exprs = op->AsListExpr()->Exprs();
for ( const auto& expr : exprs )
expr->EvalIntoAggregate(type, aggr, f);
aggr->AsTableVal()->InitDefaultFunc(f);
return aggr;
}
Val* TableConstructorExpr::InitVal(const BroType* t, Val* aggr) const
{
if ( IsError() )
return 0;
TableType* tt = Type()->AsTableType();
TableVal* tval = aggr ? aggr->AsTableVal() : new TableVal(tt, attrs);
const expr_list& exprs = op->AsListExpr()->Exprs();
for ( const auto& expr : exprs )
expr->EvalIntoAggregate(t, tval, 0);
return tval;
}
void TableConstructorExpr::ExprDescribe(ODesc* d) const
{
d->Add("table(");
op->Describe(d);
d->Add(")");
}
SetConstructorExpr::SetConstructorExpr(ListExpr* constructor_list,
attr_list* arg_attrs, BroType* arg_type)
: UnaryExpr(EXPR_SET_CONSTRUCTOR, constructor_list)
{
attrs = 0;
if ( IsError() )
return;
if ( arg_type )
{
if ( ! arg_type->IsSet() )
{
Error("bad set constructor type", arg_type);
SetError();
return;
}
SetType(arg_type->Ref());
}
else
{
if ( constructor_list->Exprs().length() == 0 )
SetType(new ::SetType(new TypeList(base_type(TYPE_ANY)), 0));
else
SetType(init_type(constructor_list));
}
if ( ! type )
SetError();
else if ( type->Tag() != TYPE_TABLE || ! type->AsTableType()->IsSet() )
SetError("values in set(...) constructor do not specify a set");
attrs = arg_attrs ? new Attributes(arg_attrs, type, false, false) : 0;
type_list* indices = type->AsTableType()->Indices()->Types();
expr_list& cle = constructor_list->Exprs();
if ( indices->length() == 1 )
{
if ( ! check_and_promote_exprs_to_type(constructor_list,
(*indices)[0]) )
ExprError("inconsistent type in set constructor");
}
else if ( indices->length() > 1 )
{
// Check/promote each expression in composite index.
loop_over_list(cle, i)
{
Expr* ce = cle[i];
ListExpr* le = ce->AsListExpr();
if ( ce->Tag() == EXPR_LIST &&
check_and_promote_exprs(le, type->AsTableType()->Indices()) )
{
if ( le != cle[i] )
cle.replace(i, le);
continue;
}
ExprError("inconsistent types in set constructor");
}
}
}
Val* SetConstructorExpr::Eval(Frame* f) const
{
if ( IsError() )
return 0;
TableVal* aggr = new TableVal(type->AsTableType(), attrs);
const expr_list& exprs = op->AsListExpr()->Exprs();
for ( const auto& expr : exprs )
{
Val* element = expr->Eval(f);
aggr->Assign(element, 0);
Unref(element);
}
return aggr;
}
Val* SetConstructorExpr::InitVal(const BroType* t, Val* aggr) const
{
if ( IsError() )
return 0;
const BroType* index_type = t->AsTableType()->Indices();
TableType* tt = Type()->AsTableType();
TableVal* tval = aggr ? aggr->AsTableVal() : new TableVal(tt, attrs);
const expr_list& exprs = op->AsListExpr()->Exprs();
for ( const auto& e : exprs )
{
Val* element = check_and_promote(e->Eval(0), index_type, 1);
if ( ! element || ! tval->Assign(element, 0) )
{
Error(fmt("initialization type mismatch in set"), e);
return 0;
}
Unref(element);
}
return tval;
}
void SetConstructorExpr::ExprDescribe(ODesc* d) const
{
d->Add("set(");
op->Describe(d);
d->Add(")");
}
VectorConstructorExpr::VectorConstructorExpr(ListExpr* constructor_list,
BroType* arg_type)
: UnaryExpr(EXPR_VECTOR_CONSTRUCTOR, constructor_list)
{
if ( IsError() )
return;
if ( arg_type )
{
if ( arg_type->Tag() != TYPE_VECTOR )
{
Error("bad vector constructor type", arg_type);
SetError();
return;
}
SetType(arg_type->Ref());
}
else
{
if ( constructor_list->Exprs().length() == 0 )
{
// vector().
// By default, assign VOID type here. A vector with
// void type set is seen as an unspecified vector.
SetType(new ::VectorType(base_type(TYPE_VOID)));
return;
}
BroType* t = merge_type_list(constructor_list);
if ( t )
{
SetType(new VectorType(t->Ref()));
Unref(t);
}
else
{
SetError();
return;
}
}
if ( ! check_and_promote_exprs_to_type(constructor_list,
type->AsVectorType()->YieldType()) )
ExprError("inconsistent types in vector constructor");
}
Val* VectorConstructorExpr::Eval(Frame* f) const
{
if ( IsError() )
return 0;
VectorVal* vec = new VectorVal(Type()->AsVectorType());
const expr_list& exprs = op->AsListExpr()->Exprs();
loop_over_list(exprs, i)
{
Expr* e = exprs[i];
Val* v = e->Eval(f);
if ( ! vec->Assign(i, v) )
{
RuntimeError(fmt("type mismatch at index %d", i));
return 0;
}
}
return vec;
}
Val* VectorConstructorExpr::InitVal(const BroType* t, Val* aggr) const
{
if ( IsError() )
return 0;
VectorType* vt = Type()->AsVectorType();
VectorVal* vec = aggr ? aggr->AsVectorVal() : new VectorVal(vt);
const expr_list& exprs = op->AsListExpr()->Exprs();
loop_over_list(exprs, i)
{
Expr* e = exprs[i];
Val* v = check_and_promote(e->Eval(0), t->YieldType(), 1);
if ( ! v || ! vec->Assign(i, v) )
{
Error(fmt("initialization type mismatch at index %d", i), e);
if ( ! aggr )
Unref(vec);
return 0;
}
}
return vec;
}
void VectorConstructorExpr::ExprDescribe(ODesc* d) const
{
d->Add("vector(");
op->Describe(d);
d->Add(")");
}
FieldAssignExpr::FieldAssignExpr(const char* arg_field_name, Expr* value)
: UnaryExpr(EXPR_FIELD_ASSIGN, value), field_name(arg_field_name)
{
op->Ref();
SetType(value->Type()->Ref());
}
void FieldAssignExpr::EvalIntoAggregate(const BroType* t, Val* aggr, Frame* f)
const
{
if ( IsError() )
return;
RecordVal* rec = aggr->AsRecordVal();
const RecordType* rt = t->AsRecordType();
Val* v = op->Eval(f);
if ( v )
{
int idx = rt->FieldOffset(field_name.c_str());
if ( idx < 0 )
reporter->InternalError("Missing record field: %s",
field_name.c_str());
rec->Assign(idx, v);
}
}
int FieldAssignExpr::IsRecordElement(TypeDecl* td) const
{
if ( td )
{
td->type = op->Type()->Ref();
td->id = copy_string(field_name.c_str());
}
return 1;
}
void FieldAssignExpr::ExprDescribe(ODesc* d) const
{
d->Add("$");
d->Add(FieldName());
d->Add("=");
op->Describe(d);
}
ArithCoerceExpr::ArithCoerceExpr(Expr* arg_op, TypeTag t)
: UnaryExpr(EXPR_ARITH_COERCE, arg_op)
{
if ( IsError() )
return;
TypeTag bt = op->Type()->Tag();
TypeTag vbt = bt;
if ( IsVector(bt) )
{
SetType(new VectorType(base_type(t)));
vbt = op->Type()->AsVectorType()->YieldType()->Tag();
}
else
SetType(base_type(t));
if ( (bt == TYPE_ENUM) != (t == TYPE_ENUM) )
ExprError("can't convert to/from enumerated type");
else if ( ! IsArithmetic(t) && ! IsBool(t) &&
t != TYPE_TIME && t != TYPE_INTERVAL )
ExprError("bad coercion");
else if ( ! IsArithmetic(bt) && ! IsBool(bt) &&
! IsArithmetic(vbt) && ! IsBool(vbt) )
ExprError("bad coercion value");
}
Val* ArithCoerceExpr::FoldSingleVal(Val* v, InternalTypeTag t) const
{
switch ( t ) {
case TYPE_INTERNAL_DOUBLE:
return new Val(v->CoerceToDouble(), TYPE_DOUBLE);
case TYPE_INTERNAL_INT:
return val_mgr->GetInt(v->CoerceToInt());
case TYPE_INTERNAL_UNSIGNED:
return val_mgr->GetCount(v->CoerceToUnsigned());
default:
RuntimeErrorWithCallStack("bad type in CoerceExpr::Fold");
return 0;
}
}
Val* ArithCoerceExpr::Fold(Val* v) const
{
InternalTypeTag t = type->InternalType();
if ( ! is_vector(v) )
{
// Our result type might be vector, in which case this
// invocation is being done per-element rather than on
// the whole vector. Correct the type tag if necessary.
if ( type->Tag() == TYPE_VECTOR )
t = Type()->AsVectorType()->YieldType()->InternalType();
return FoldSingleVal(v, t);
}
t = Type()->AsVectorType()->YieldType()->InternalType();
VectorVal* vv = v->AsVectorVal();
VectorVal* result = new VectorVal(Type()->AsVectorType());
for ( unsigned int i = 0; i < vv->Size(); ++i )
{
Val* elt = vv->Lookup(i);
if ( elt )
result->Assign(i, FoldSingleVal(elt, t));
else
result->Assign(i, 0);
}
return result;
}
RecordCoerceExpr::RecordCoerceExpr(Expr* op, RecordType* r)
: UnaryExpr(EXPR_RECORD_COERCE, op)
{
map_size = 0;
map = 0;
if ( IsError() )
return;
SetType(r->Ref());
if ( Type()->Tag() != TYPE_RECORD )
ExprError("coercion to non-record");
else if ( op->Type()->Tag() != TYPE_RECORD )
ExprError("coercion of non-record to record");
else
{
RecordType* t_r = type->AsRecordType();
RecordType* sub_r = op->Type()->AsRecordType();
map_size = t_r->NumFields();
map = new int[map_size];
int i;
for ( i = 0; i < map_size; ++i )
map[i] = -1; // -1 = field is not mapped
for ( i = 0; i < sub_r->NumFields(); ++i )
{
int t_i = t_r->FieldOffset(sub_r->FieldName(i));
if ( t_i < 0 )
{
ExprError(fmt("orphaned field \"%s\" in record coercion",
sub_r->FieldName(i)));
break;
}
BroType* sub_t_i = sub_r->FieldType(i);
BroType* sup_t_i = t_r->FieldType(t_i);
if ( ! same_type(sup_t_i, sub_t_i) )
{
auto is_arithmetic_promotable = [](BroType* sup, BroType* sub) -> bool
{
auto sup_tag = sup->Tag();
auto sub_tag = sub->Tag();
if ( ! BothArithmetic(sup_tag, sub_tag) )
return false;
if ( sub_tag == TYPE_DOUBLE && IsIntegral(sup_tag) )
return false;
if ( sub_tag == TYPE_INT && sup_tag == TYPE_COUNT )
return false;
return true;
};
auto is_record_promotable = [](BroType* sup, BroType* sub) -> bool
{
if ( sup->Tag() != TYPE_RECORD )
return false;
if ( sub->Tag() != TYPE_RECORD )
return false;
return record_promotion_compatible(sup->AsRecordType(),
sub->AsRecordType());
};
if ( ! is_arithmetic_promotable(sup_t_i, sub_t_i) &&
! is_record_promotable(sup_t_i, sub_t_i) )
{
string error_msg = fmt(
"type clash for field \"%s\"", sub_r->FieldName(i));
Error(error_msg.c_str(), sub_t_i);
SetError();
break;
}
}
map[t_i] = i;
}
if ( IsError() )
return;
for ( i = 0; i < map_size; ++i )
{
if ( map[i] == -1 )
{
if ( ! t_r->FieldDecl(i)->FindAttr(ATTR_OPTIONAL) )
{
string error_msg = fmt(
"non-optional field \"%s\" missing", t_r->FieldName(i));
Error(error_msg.c_str());
SetError();
break;
}
}
else if ( t_r->IsFieldDeprecated(i) )
reporter->Warning("%s", t_r->GetFieldDeprecationWarning(i, false).c_str());
}
}
}
RecordCoerceExpr::~RecordCoerceExpr()
{
delete [] map;
}
Val* RecordCoerceExpr::InitVal(const BroType* t, Val* aggr) const
{
Val* v = Eval(0);
if ( v )
{
RecordVal* rv = v->AsRecordVal();
RecordVal* ar = rv->CoerceTo(t->AsRecordType(), aggr);
if ( ar )
{
Unref(rv);
return ar;
}
}
Error("bad record initializer");
return 0;
}
Val* RecordCoerceExpr::Fold(Val* v) const
{
RecordVal* val = new RecordVal(Type()->AsRecordType());
RecordVal* rv = v->AsRecordVal();
for ( int i = 0; i < map_size; ++i )
{
if ( map[i] >= 0 )
{
Val* rhs = rv->Lookup(map[i]);
if ( ! rhs )
{
const Attr* def = rv->Type()->AsRecordType()->FieldDecl(
map[i])->FindAttr(ATTR_DEFAULT);
if ( def )
rhs = def->AttrExpr()->Eval(0);
}
if ( rhs )
rhs = rhs->Ref();
assert(rhs || Type()->AsRecordType()->FieldDecl(i)->FindAttr(ATTR_OPTIONAL));
if ( ! rhs )
{
// Optional field is missing.
val->Assign(i, 0);
continue;
}
BroType* rhs_type = rhs->Type();
RecordType* val_type = val->Type()->AsRecordType();
BroType* field_type = val_type->FieldType(i);
if ( rhs_type->Tag() == TYPE_RECORD &&
field_type->Tag() == TYPE_RECORD &&
! same_type(rhs_type, field_type) )
{
Val* new_val = rhs->AsRecordVal()->CoerceTo(
field_type->AsRecordType());
if ( new_val )
{
Unref(rhs);
rhs = new_val;
}
}
else if ( BothArithmetic(rhs_type->Tag(), field_type->Tag()) &&
! same_type(rhs_type, field_type) )
{
if ( Val* new_val = check_and_promote(rhs, field_type, false, op->GetLocationInfo()) )
{
// Don't call unref here on rhs because check_and_promote already called it.
rhs = new_val;
}
else
{
Unref(val);
RuntimeError("Failed type conversion");
}
}
val->Assign(i, rhs);
}
else
{
const Attr* def =
Type()->AsRecordType()->FieldDecl(i)->FindAttr(ATTR_DEFAULT);
if ( def )
{
Val* def_val = def->AttrExpr()->Eval(0);
BroType* def_type = def_val->Type();
BroType* field_type = Type()->AsRecordType()->FieldType(i);
if ( def_type->Tag() == TYPE_RECORD &&
field_type->Tag() == TYPE_RECORD &&
! same_type(def_type, field_type) )
{
Val* tmp = def_val->AsRecordVal()->CoerceTo(
field_type->AsRecordType());
if ( tmp )
{
Unref(def_val);
def_val = tmp;
}
}
val->Assign(i, def_val);
}
else
val->Assign(i, 0);
}
}
return val;
}
TableCoerceExpr::TableCoerceExpr(Expr* op, TableType* r)
: UnaryExpr(EXPR_TABLE_COERCE, op)
{
if ( IsError() )
return;
SetType(r->Ref());
if ( Type()->Tag() != TYPE_TABLE )
ExprError("coercion to non-table");
else if ( op->Type()->Tag() != TYPE_TABLE )
ExprError("coercion of non-table/set to table/set");
}
TableCoerceExpr::~TableCoerceExpr()
{
}
Val* TableCoerceExpr::Fold(Val* v) const
{
TableVal* tv = v->AsTableVal();
if ( tv->Size() > 0 )
RuntimeErrorWithCallStack("coercion of non-empty table/set");
return new TableVal(Type()->AsTableType(), tv->Attrs());
}
VectorCoerceExpr::VectorCoerceExpr(Expr* op, VectorType* v)
: UnaryExpr(EXPR_VECTOR_COERCE, op)
{
if ( IsError() )
return;
SetType(v->Ref());
if ( Type()->Tag() != TYPE_VECTOR )
ExprError("coercion to non-vector");
else if ( op->Type()->Tag() != TYPE_VECTOR )
ExprError("coercion of non-vector to vector");
}
VectorCoerceExpr::~VectorCoerceExpr()
{
}
Val* VectorCoerceExpr::Fold(Val* v) const
{
VectorVal* vv = v->AsVectorVal();
if ( vv->Size() > 0 )
RuntimeErrorWithCallStack("coercion of non-empty vector");
return new VectorVal(Type()->Ref()->AsVectorType());
}
FlattenExpr::FlattenExpr(Expr* arg_op)
: UnaryExpr(EXPR_FLATTEN, arg_op)
{
if ( IsError() )
return;
BroType* t = op->Type();
if ( t->Tag() != TYPE_RECORD )
Internal("bad type in FlattenExpr::FlattenExpr");
RecordType* rt = t->AsRecordType();
num_fields = rt->NumFields();
TypeList* tl = new TypeList();
for ( int i = 0; i < num_fields; ++i )
tl->Append(rt->FieldType(i)->Ref());
Unref(rt);
SetType(tl);
}
Val* FlattenExpr::Fold(Val* v) const
{
RecordVal* rv = v->AsRecordVal();
ListVal* l = new ListVal(TYPE_ANY);
for ( int i = 0; i < num_fields; ++i )
{
Val* fv = rv->Lookup(i);
if ( fv )
{
l->Append(fv->Ref());
continue;
}
const RecordType* rv_t = rv->Type()->AsRecordType();
const Attr* fa = rv_t->FieldDecl(i)->FindAttr(ATTR_DEFAULT);
if ( fa )
l->Append(fa->AttrExpr()->Eval(0));
else
RuntimeError("missing field value");
}
return l;
}
ScheduleTimer::ScheduleTimer(EventHandlerPtr arg_event, val_list* arg_args,
double t, TimerMgr* arg_tmgr)
: Timer(t, TIMER_SCHEDULE),
event(arg_event),
args(std::move(*arg_args)),
tmgr(arg_tmgr)
{
delete arg_args;
}
ScheduleTimer::~ScheduleTimer()
{
}
void ScheduleTimer::Dispatch(double /* t */, int /* is_expire */)
{
mgr.QueueEvent(event, std::move(args), SOURCE_LOCAL, 0, tmgr);
}
ScheduleExpr::ScheduleExpr(Expr* arg_when, EventExpr* arg_event)
: Expr(EXPR_SCHEDULE)
{
when = arg_when;
event = arg_event;
if ( IsError() || when->IsError() || event->IsError() )
return;
TypeTag bt = when->Type()->Tag();
if ( bt != TYPE_TIME && bt != TYPE_INTERVAL )
ExprError("schedule expression requires a time or time interval");
else
SetType(base_type(TYPE_TIMER));
}
ScheduleExpr::~ScheduleExpr()
{
Unref(when);
Unref(event);
}
int ScheduleExpr::IsPure() const
{
return 0;
}
Val* ScheduleExpr::Eval(Frame* f) const
{
if ( terminating )
return 0;
Val* when_val = when->Eval(f);
if ( ! when_val )
return 0;
double dt = when_val->InternalDouble();
if ( when->Type()->Tag() == TYPE_INTERVAL )
dt += network_time;
val_list* args = eval_list(f, event->Args());
if ( args )
{
TimerMgr* tmgr = mgr.CurrentTimerMgr();
if ( ! tmgr )
tmgr = timer_mgr;
tmgr->Add(new ScheduleTimer(event->Handler(), args, dt, tmgr));
}
Unref(when_val);
return 0;
}
TraversalCode ScheduleExpr::Traverse(TraversalCallback* cb) const
{
TraversalCode tc = cb->PreExpr(this);
HANDLE_TC_EXPR_PRE(tc);
tc = when->Traverse(cb);
HANDLE_TC_EXPR_PRE(tc);
tc = event->Traverse(cb);
HANDLE_TC_EXPR_PRE(tc);
tc = cb->PostExpr(this);
HANDLE_TC_EXPR_POST(tc);
}
void ScheduleExpr::ExprDescribe(ODesc* d) const
{
if ( d->IsReadable() )
d->AddSP("schedule");
when->Describe(d);
d->SP();
if ( d->IsReadable() )
{
d->Add("{");
d->PushIndent();
event->Describe(d);
d->PopIndent();
d->Add("}");
}
else
event->Describe(d);
}
InExpr::InExpr(Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(EXPR_IN, arg_op1, arg_op2)
{
if ( IsError() )
return;
if ( op1->Type()->Tag() == TYPE_PATTERN )
{
if ( op2->Type()->Tag() != TYPE_STRING )
{
op2->Type()->Error("pattern requires string index", op1);
SetError();
}
else
SetType(base_type(TYPE_BOOL));
}
else if ( op1->Type()->Tag() == TYPE_RECORD )
{
if ( op2->Type()->Tag() != TYPE_TABLE )
{
op2->Type()->Error("table/set required");
SetError();
}
else
{
const BroType* t1 = op1->Type();
const TypeList* it =
op2->Type()->AsTableType()->Indices();
if ( ! same_type(t1, it) )
{
t1->Error("indexing mismatch", op2->Type());
SetError();
}
else
SetType(base_type(TYPE_BOOL));
}
}
else if ( op1->Type()->Tag() == TYPE_STRING &&
op2->Type()->Tag() == TYPE_STRING )
SetType(base_type(TYPE_BOOL));
else
{
// Check for: <addr> in <subnet>
// <addr> in set[subnet]
// <addr> in table[subnet] of ...
if ( op1->Type()->Tag() == TYPE_ADDR )
{
if ( op2->Type()->Tag() == TYPE_SUBNET )
{
SetType(base_type(TYPE_BOOL));
return;
}
if ( op2->Type()->Tag() == TYPE_TABLE &&
op2->Type()->AsTableType()->IsSubNetIndex() )
{
SetType(base_type(TYPE_BOOL));
return;
}
}
if ( op1->Tag() != EXPR_LIST )
op1 = new ListExpr(op1);
ListExpr* lop1 = op1->AsListExpr();
if ( ! op2->Type()->MatchesIndex(lop1) )
SetError("not an index type");
else
{
op1 = lop1;
SetType(base_type(TYPE_BOOL));
}
}
}
Val* InExpr::Fold(Val* v1, Val* v2) const
{
if ( v1->Type()->Tag() == TYPE_PATTERN )
{
RE_Matcher* re = v1->AsPattern();
const BroString* s = v2->AsString();
return val_mgr->GetBool(re->MatchAnywhere(s) != 0);
}
if ( v2->Type()->Tag() == TYPE_STRING )
{
const BroString* s1 = v1->AsString();
const BroString* s2 = v2->AsString();
// Could do better here e.g. Boyer-Moore if done repeatedly.
return val_mgr->GetBool(strstr_n(s2->Len(), s2->Bytes(), s1->Len(), reinterpret_cast<const unsigned char*>(s1->CheckString())) != -1);
}
if ( v1->Type()->Tag() == TYPE_ADDR &&
v2->Type()->Tag() == TYPE_SUBNET )
return val_mgr->GetBool(v2->AsSubNetVal()->Contains(v1->AsAddr()));
Val* res;
if ( is_vector(v2) )
res = v2->AsVectorVal()->Lookup(v1);
else
res = v2->AsTableVal()->Lookup(v1, false);
if ( res )
return val_mgr->GetBool(1);
else
return val_mgr->GetBool(0);
}
CallExpr::CallExpr(Expr* arg_func, ListExpr* arg_args, bool in_hook)
: Expr(EXPR_CALL)
{
func = arg_func;
args = arg_args;
if ( func->IsError() || args->IsError() )
{
SetError();
return;
}
BroType* func_type = func->Type();
if ( ! IsFunc(func_type->Tag()) )
{
func->Error("not a function");
SetError();
return;
}
if ( func_type->AsFuncType()->Flavor() == FUNC_FLAVOR_HOOK && ! in_hook )
{
func->Error("hook cannot be called directly, use hook operator");
SetError();
return;
}
if ( ! func_type->MatchesIndex(args) )
SetError("argument type mismatch in function call");
else
{
BroType* yield = func_type->YieldType();
if ( ! yield )
{
switch ( func_type->AsFuncType()->Flavor() ) {
case FUNC_FLAVOR_FUNCTION:
Error("function has no yield type");
SetError();
break;
case FUNC_FLAVOR_EVENT:
Error("event called in expression, use event statement instead");
SetError();
break;
case FUNC_FLAVOR_HOOK:
Error("hook has no yield type");
SetError();
break;
default:
Error("invalid function flavor");
SetError();
break;
}
}
else
SetType(yield->Ref());
// Check for call to built-ins that can be statically
// analyzed.
Val* func_val;
if ( func->Tag() == EXPR_NAME &&
// This is cheating, but without it processing gets
// quite confused regarding "value used but not set"
// run-time errors when we apply this analysis during
// parsing. Really we should instead do it after we've
// parsed the entire set of scripts.
streq(((NameExpr*) func)->Id()->Name(), "fmt") &&
// The following is needed because fmt might not yet
// be bound as a name.
did_builtin_init &&
(func_val = func->Eval(0)) )
{
::Func* f = func_val->AsFunc();
if ( f->GetKind() == Func::BUILTIN_FUNC &&
! check_built_in_call((BuiltinFunc*) f, this) )
SetError();
}
}
}
CallExpr::~CallExpr()
{
Unref(func);
Unref(args);
}
int CallExpr::IsPure() const
{
if ( IsError() )
return 1;
if ( ! func->IsPure() )
return 0;
Val* func_val = func->Eval(0);
if ( ! func_val )
return 0;
::Func* f = func_val->AsFunc();
// Only recurse for built-in functions, as recursing on script
// functions can lead to infinite recursion if the function being
// called here happens to be recursive (either directly
// or indirectly).
int pure = 0;
if ( f->GetKind() == Func::BUILTIN_FUNC )
pure = f->IsPure() && args->IsPure();
Unref(func_val);
return pure;
}
Val* CallExpr::Eval(Frame* f) const
{
if ( IsError() )
return 0;
// If we are inside a trigger condition, we may have already been
// called, delayed, and then produced a result which is now cached.
// Check for that.
if ( f )
{
trigger::Trigger* trigger = f->GetTrigger();
if ( trigger )
{
Val* v = trigger->Lookup(this);
if ( v )
{
DBG_LOG(DBG_NOTIFIERS,
"%s: provides cached function result",
trigger->Name());
return v->Ref();
}
}
}
Val* ret = 0;
Val* func_val = func->Eval(f);
val_list* v = eval_list(f, args);
if ( func_val && v )
{
const ::Func* func = func_val->AsFunc();
const CallExpr* current_call = f ? f->GetCall() : 0;
if ( f )
f->SetCall(this);
ret = func->Call(v, f);
if ( f )
f->SetCall(current_call);
// Don't Unref() the arguments, as Func::Call already did that.
delete v;
}
else
delete_vals(v);
Unref(func_val);
return ret;
}
TraversalCode CallExpr::Traverse(TraversalCallback* cb) const
{
TraversalCode tc = cb->PreExpr(this);
HANDLE_TC_EXPR_PRE(tc);
tc = func->Traverse(cb);
HANDLE_TC_EXPR_PRE(tc);
tc = args->Traverse(cb);
HANDLE_TC_EXPR_PRE(tc);
tc = cb->PostExpr(this);
HANDLE_TC_EXPR_POST(tc);
}
void CallExpr::ExprDescribe(ODesc* d) const
{
func->Describe(d);
if ( d->IsReadable() || d->IsPortable() )
{
d->Add("(");
args->Describe(d);
d->Add(")");
}
else
args->Describe(d);
}
LambdaExpr::LambdaExpr(std::unique_ptr<function_ingredients> arg_ing,
id_list arg_outer_ids) : Expr(EXPR_LAMBDA)
{
ingredients = std::move(arg_ing);
outer_ids = std::move(arg_outer_ids);
SetType(ingredients->id->Type()->Ref());
// Install a dummy version of the function globally for use only
// when broker provides a closure.
::Ref(ingredients->body);
BroFunc* dummy_func = new BroFunc(
ingredients->id,
ingredients->body,
ingredients->inits,
ingredients->frame_size,
ingredients->priority);
dummy_func->SetOuterIDs(outer_ids);
// Get the body's "string" representation.
ODesc d;
dummy_func->Describe(&d);
for ( ; ; )
{
uint64_t h[2];
internal_md5(d.Bytes(), d.Len(), reinterpret_cast<unsigned char*>(h));
my_name = "lambda_<" + std::to_string(h[0]) + ">";
auto fullname = make_full_var_name(current_module.data(), my_name.data());
auto id = global_scope()->Lookup(fullname);
if ( id )
// Just try again to make a unique lambda name. If two peer
// processes need to agree on the same lambda name, this assumes
// they're loading the same scripts and thus have the same hash
// collisions.
d.Add(" ");
else
break;
}
// Install that in the global_scope
ID* id = install_ID(my_name.c_str(), current_module.c_str(), true, false);
// Update lamb's name
dummy_func->SetName(my_name.c_str());
Val* v = new Val(dummy_func);
Unref(dummy_func);
id->SetVal(v); // id will unref v when its done.
id->SetType(ingredients->id->Type()->Ref());
id->SetConst();
}
Val* LambdaExpr::Eval(Frame* f) const
{
::Ref(ingredients->body);
BroFunc* lamb = new BroFunc(
ingredients->id,
ingredients->body,
ingredients->inits,
ingredients->frame_size,
ingredients->priority);
lamb->AddClosure(outer_ids, f);
// Set name to corresponding dummy func.
// Allows for lookups by the receiver.
lamb->SetName(my_name.c_str());
auto rval = new Val(lamb);
Unref(lamb);
return rval;
}
void LambdaExpr::ExprDescribe(ODesc* d) const
{
d->Add(expr_name(Tag()));
ingredients->body->Describe(d);
}
TraversalCode LambdaExpr::Traverse(TraversalCallback* cb) const
{
TraversalCode tc = cb->PreExpr(this);
HANDLE_TC_EXPR_PRE(tc);
tc = ingredients->body->Traverse(cb);
HANDLE_TC_STMT_PRE(tc);
tc = cb->PostExpr(this);
HANDLE_TC_EXPR_POST(tc);
}
EventExpr::EventExpr(const char* arg_name, ListExpr* arg_args)
: Expr(EXPR_EVENT)
{
name = arg_name;
args = arg_args;
EventHandler* h = event_registry->Lookup(name);
if ( ! h )
{
h = new EventHandler(name.c_str());
event_registry->Register(h);
}
h->SetUsed();
handler = h;
if ( args->IsError() )
{
SetError();
return;
}
FuncType* func_type = h->FType();
if ( ! func_type )
{
Error("not an event");
SetError();
return;
}
if ( ! func_type->MatchesIndex(args) )
SetError("argument type mismatch in event invocation");
else
{
if ( func_type->YieldType() )
{
Error("function invoked as an event");
SetError();
}
}
}
EventExpr::~EventExpr()
{
Unref(args);
}
Val* EventExpr::Eval(Frame* f) const
{
if ( IsError() )
return 0;
val_list* v = eval_list(f, args);
mgr.QueueEvent(handler, std::move(*v));
delete v;
return 0;
}
TraversalCode EventExpr::Traverse(TraversalCallback* cb) const
{
TraversalCode tc = cb->PreExpr(this);
HANDLE_TC_EXPR_PRE(tc);
tc = args->Traverse(cb);
HANDLE_TC_EXPR_PRE(tc);
tc = cb->PostExpr(this);
HANDLE_TC_EXPR_POST(tc);
}
void EventExpr::ExprDescribe(ODesc* d) const
{
d->Add(name.c_str());
if ( d->IsReadable() || d->IsPortable() )
{
d->Add("(");
args->Describe(d);
d->Add(")");
}
else
args->Describe(d);
}
ListExpr::ListExpr() : Expr(EXPR_LIST)
{
SetType(new TypeList());
}
ListExpr::ListExpr(Expr* e) : Expr(EXPR_LIST)
{
SetType(new TypeList());
Append(e);
}
ListExpr::~ListExpr()
{
for ( const auto& expr: exprs )
Unref(expr);
}
void ListExpr::Append(Expr* e)
{
exprs.push_back(e);
((TypeList*) type)->Append(e->Type()->Ref());
}
int ListExpr::IsPure() const
{
for ( const auto& expr : exprs )
if ( ! expr->IsPure() )
return 0;
return 1;
}
int ListExpr::AllConst() const
{
for ( const auto& expr : exprs )
if ( ! expr->IsConst() )
return 0;
return 1;
}
Val* ListExpr::Eval(Frame* f) const
{
ListVal* v = new ListVal(TYPE_ANY);
for ( const auto& expr : exprs )
{
Val* ev = expr->Eval(f);
if ( ! ev )
{
RuntimeError("uninitialized list value");
Unref(v);
return 0;
}
v->Append(ev);
}
return v;
}
BroType* ListExpr::InitType() const
{
if ( exprs.length() == 0 )
{
Error("empty list in untyped initialization");
return 0;
}
if ( exprs[0]->IsRecordElement(0) )
{
type_decl_list* types = new type_decl_list(exprs.length());
for ( const auto& expr : exprs )
{
TypeDecl* td = new TypeDecl(0, 0);
if ( ! expr->IsRecordElement(td) )
{
expr->Error("record element expected");
delete td;
delete types;
return 0;
}
types->push_back(td);
}
return new RecordType(types);
}
else
{
TypeList* tl = new TypeList();
for ( const auto& e : exprs )
{
BroType* ti = e->Type();
// Collapse any embedded sets or lists.
if ( ti->IsSet() || ti->Tag() == TYPE_LIST )
{
TypeList* til = ti->IsSet() ?
ti->AsSetType()->Indices() :
ti->AsTypeList();
if ( ! til->IsPure() ||
! til->AllMatch(til->PureType(), 1) )
tl->Append(til->Ref());
else
tl->Append(til->PureType()->Ref());
}
else
tl->Append(ti->Ref());
}
return tl;
}
}
Val* ListExpr::InitVal(const BroType* t, Val* aggr) const
{
// While fairly similar to the EvalIntoAggregate() code,
// we keep this separate since it also deals with initialization
// idioms such as embedded aggregates and cross-product
// expansion.
if ( IsError() )
return 0;
// Check whether each element of this list itself matches t,
// in which case we should expand as a ListVal.
if ( ! aggr && type->AsTypeList()->AllMatch(t, 1) )
{
ListVal* v = new ListVal(TYPE_ANY);
const type_list* tl = type->AsTypeList()->Types();
if ( exprs.length() != tl->length() )
{
Error("index mismatch", t);
Unref(v);
return 0;
}
loop_over_list(exprs, i)
{
Val* vi = exprs[i]->InitVal((*tl)[i], 0);
if ( ! vi )
{
Unref(v);
return 0;
}
v->Append(vi);
}
return v;
}
if ( t->Tag() == TYPE_LIST )
{
if ( aggr )
{
Error("bad use of list in initialization", t);
return 0;
}
const type_list* tl = t->AsTypeList()->Types();
if ( exprs.length() != tl->length() )
{
Error("index mismatch", t);
return 0;
}
ListVal* v = new ListVal(TYPE_ANY);
loop_over_list(exprs, i)
{
Val* vi = exprs[i]->InitVal((*tl)[i], 0);
if ( ! vi )
{
Unref(v);
return 0;
}
v->Append(vi);
}
return v;
}
if ( t->Tag() != TYPE_RECORD && t->Tag() != TYPE_TABLE &&
t->Tag() != TYPE_VECTOR )
{
if ( exprs.length() == 1 )
// Allow "global x:int = { 5 }"
return exprs[0]->InitVal(t, aggr);
else
{
Error("aggregate initializer for scalar type", t);
return 0;
}
}
if ( ! aggr )
Internal("missing aggregate in ListExpr::InitVal");
if ( t->IsSet() )
return AddSetInit(t, aggr);
if ( t->Tag() == TYPE_VECTOR )
{
// v: vector = [10, 20, 30];
VectorVal* vec = aggr->AsVectorVal();
loop_over_list(exprs, i)
{
Expr* e = exprs[i];
check_and_promote_expr(e, vec->Type()->AsVectorType()->YieldType());
Val* v = e->Eval(0);
if ( ! vec->Assign(i, v) )
{
e->Error(fmt("type mismatch at index %d", i));
return 0;
}
}
return aggr;
}
// If we got this far, then it's either a table or record
// initialization. Both of those involve AssignExpr's, which
// know how to add themselves to a table or record. Another
// possibility is an expression that evaluates itself to a
// table, which we can then add to the aggregate.
for ( const auto& e : exprs )
{
if ( e->Tag() == EXPR_ASSIGN || e->Tag() == EXPR_FIELD_ASSIGN )
{
if ( ! e->InitVal(t, aggr) )
return 0;
}
else
{
if ( t->Tag() == TYPE_RECORD )
{
e->Error("bad record initializer", t);
return 0;
}
Val* v = e->Eval(0);
if ( ! same_type(v->Type(), t) )
{
v->Type()->Error("type clash in table initializer", t);
return 0;
}
if ( ! v->AsTableVal()->AddTo(aggr->AsTableVal(), 1) )
return 0;
}
}
return aggr;
}
Val* ListExpr::AddSetInit(const BroType* t, Val* aggr) const
{
if ( aggr->Type()->Tag() != TYPE_TABLE )
Internal("bad aggregate in ListExpr::InitVal");
TableVal* tv = aggr->AsTableVal();
const TableType* tt = tv->Type()->AsTableType();
const TypeList* it = tt->Indices();
for ( const auto& expr : exprs )
{
Val* element;
if ( expr->Type()->IsSet() )
// A set to flatten.
element = expr->Eval(0);
else if ( expr->Type()->Tag() == TYPE_LIST )
element = expr->InitVal(it, 0);
else
element = expr->InitVal((*it->Types())[0], 0);
if ( ! element )
return 0;
if ( element->Type()->IsSet() )
{
if ( ! same_type(element->Type(), t) )
{
element->Error("type clash in set initializer", t);
return 0;
}
if ( ! element->AsTableVal()->AddTo(tv, 1) )
return 0;
continue;
}
if ( expr->Type()->Tag() == TYPE_LIST )
element = check_and_promote(element, it, 1);
else
element = check_and_promote(element, (*it->Types())[0], 1);
if ( ! element )
return 0;
if ( ! tv->ExpandAndInit(element, 0) )
{
Unref(element);
Unref(tv);
return 0;
}
Unref(element);
}
return tv;
}
void ListExpr::ExprDescribe(ODesc* d) const
{
d->AddCount(exprs.length());
loop_over_list(exprs, i)
{
if ( (d->IsReadable() || d->IsPortable()) && i > 0 )
d->Add(", ");
exprs[i]->Describe(d);
}
}
Expr* ListExpr::MakeLvalue()
{
for ( const auto & expr : exprs )
if ( expr->Tag() != EXPR_NAME )
ExprError("can only assign to list of identifiers");
return new RefExpr(this);
}
void ListExpr::Assign(Frame* f, Val* v)
{
ListVal* lv = v->AsListVal();
if ( exprs.length() != lv->Vals()->length() )
RuntimeError("mismatch in list lengths");
loop_over_list(exprs, i)
exprs[i]->Assign(f, (*lv->Vals())[i]->Ref());
Unref(lv);
}
TraversalCode ListExpr::Traverse(TraversalCallback* cb) const
{
TraversalCode tc = cb->PreExpr(this);
HANDLE_TC_EXPR_PRE(tc);
for ( const auto& expr : exprs )
{
tc = expr->Traverse(cb);
HANDLE_TC_EXPR_PRE(tc);
}
tc = cb->PostExpr(this);
HANDLE_TC_EXPR_POST(tc);
}
RecordAssignExpr::RecordAssignExpr(Expr* record, Expr* init_list, int is_init)
{
const expr_list& inits = init_list->AsListExpr()->Exprs();
RecordType* lhs = record->Type()->AsRecordType();
// The inits have two forms:
// 1) other records -- use all matching field names+types
// 2) a string indicating the field name, then (as the next element)
// the value to use for that field.
for ( const auto& init : inits )
{
if ( init->Type()->Tag() == TYPE_RECORD )
{
RecordType* t = init->Type()->AsRecordType();
for ( int j = 0; j < t->NumFields(); ++j )
{
const char* field_name = t->FieldName(j);
int field = lhs->FieldOffset(field_name);
if ( field >= 0 &&
same_type(lhs->FieldType(field), t->FieldType(j)) )
{
FieldExpr* fe_lhs = new FieldExpr(record, field_name);
FieldExpr* fe_rhs = new FieldExpr(init, field_name);
Append(get_assign_expr(fe_lhs->Ref(), fe_rhs->Ref(), is_init));
}
}
}
else if ( init->Tag() == EXPR_FIELD_ASSIGN )
{
FieldAssignExpr* rf = (FieldAssignExpr*) init;
rf->Ref();
const char* field_name = ""; // rf->FieldName();
if ( lhs->HasField(field_name) )
{
FieldExpr* fe_lhs = new FieldExpr(record, field_name);
Expr* fe_rhs = rf->Op();
Append(get_assign_expr(fe_lhs->Ref(), fe_rhs, is_init));
}
else
{
string s = "No such field '";
s += field_name;
s += "'";
init_list->SetError(s.c_str());
}
}
else
{
init_list->SetError("bad record initializer");
return;
}
}
}
CastExpr::CastExpr(Expr* arg_op, BroType* t) : UnaryExpr(EXPR_CAST, arg_op)
{
auto stype = Op()->Type();
::Ref(t);
SetType(t);
if ( ! can_cast_value_to_type(stype, t) )
ExprError("cast not supported");
}
Val* CastExpr::Eval(Frame* f) const
{
if ( IsError() )
return 0;
Val* v = op->Eval(f);
if ( ! v )
return 0;
Val* nv = cast_value_to_type(v, Type());
if ( nv )
{
Unref(v);
return nv;
}
ODesc d;
d.Add("invalid cast of value with type '");
v->Type()->Describe(&d);
d.Add("' to type '");
Type()->Describe(&d);
d.Add("'");
if ( same_type(v->Type(), bro_broker::DataVal::ScriptDataType()) &&
! v->AsRecordVal()->Lookup(0) )
d.Add(" (nil $data field)");
Unref(v);
RuntimeError(d.Description());
return 0; // not reached.
}
void CastExpr::ExprDescribe(ODesc* d) const
{
Op()->Describe(d);
d->Add(" as ");
Type()->Describe(d);
}
IsExpr::IsExpr(Expr* arg_op, BroType* arg_t) : UnaryExpr(EXPR_IS, arg_op)
{
t = arg_t;
::Ref(t);
SetType(base_type(TYPE_BOOL));
}
IsExpr::~IsExpr()
{
Unref(t);
}
Val* IsExpr::Fold(Val* v) const
{
if ( IsError() )
return 0;
if ( can_cast_value_to_type(v, t) )
return val_mgr->GetBool(1);
else
return val_mgr->GetBool(0);
}
void IsExpr::ExprDescribe(ODesc* d) const
{
Op()->Describe(d);
d->Add(" is ");
t->Describe(d);
}
Expr* get_assign_expr(Expr* op1, Expr* op2, int is_init)
{
if ( op1->Type()->Tag() == TYPE_RECORD &&
op2->Type()->Tag() == TYPE_LIST )
return new RecordAssignExpr(op1, op2, is_init);
else if ( op1->Tag() == EXPR_INDEX && op1->AsIndexExpr()->IsSlice() )
return new IndexSliceAssignExpr(op1, op2, is_init);
else
return new AssignExpr(op1, op2, is_init);
}
int check_and_promote_expr(Expr*& e, BroType* t)
{
BroType* et = e->Type();
TypeTag e_tag = et->Tag();
TypeTag t_tag = t->Tag();
if ( t->Tag() == TYPE_ANY )
return 1;
if ( EitherArithmetic(t_tag, e_tag) )
{
if ( e_tag == t_tag )
return 1;
if ( ! BothArithmetic(t_tag, e_tag) )
{
t->Error("arithmetic mixed with non-arithmetic", e);
return 0;
}
TypeTag mt = max_type(t_tag, e_tag);
if ( mt != t_tag )
{
t->Error("over-promotion of arithmetic value", e);
return 0;
}
e = new ArithCoerceExpr(e, t_tag);
return 1;
}
if ( t->Tag() == TYPE_RECORD && et->Tag() == TYPE_RECORD )
{
RecordType* t_r = t->AsRecordType();
RecordType* et_r = et->AsRecordType();
if ( same_type(t, et) )
{
// Make sure the attributes match as well.
for ( int i = 0; i < t_r->NumFields(); ++i )
{
const TypeDecl* td1 = t_r->FieldDecl(i);
const TypeDecl* td2 = et_r->FieldDecl(i);
if ( same_attrs(td1->attrs, td2->attrs) )
// Everything matches perfectly.
return 1;
}
}
if ( record_promotion_compatible(t_r, et_r) )
{
e = new RecordCoerceExpr(e, t_r);
return 1;
}
t->Error("incompatible record types", e);
return 0;
}
if ( ! same_type(t, et) )
{
if ( t->Tag() == TYPE_TABLE && et->Tag() == TYPE_TABLE &&
et->AsTableType()->IsUnspecifiedTable() )
{
e = new TableCoerceExpr(e, t->AsTableType());
return 1;
}
if ( t->Tag() == TYPE_VECTOR && et->Tag() == TYPE_VECTOR &&
et->AsVectorType()->IsUnspecifiedVector() )
{
e = new VectorCoerceExpr(e, t->AsVectorType());
return 1;
}
t->Error("type clash", e);
return 0;
}
return 1;
}
int check_and_promote_exprs(ListExpr*& elements, TypeList* types)
{
expr_list& el = elements->Exprs();
const type_list* tl = types->Types();
if ( tl->length() == 1 && (*tl)[0]->Tag() == TYPE_ANY )
return 1;
if ( el.length() != tl->length() )
{
types->Error("indexing mismatch", elements);
return 0;
}
loop_over_list(el, i)
{
Expr* e = el[i];
if ( ! check_and_promote_expr(e, (*tl)[i]) )
{
e->Error("type mismatch", (*tl)[i]);
return 0;
}
if ( e != el[i] )
el.replace(i, e);
}
return 1;
}
int check_and_promote_args(ListExpr*& args, RecordType* types)
{
expr_list& el = args->Exprs();
int ntypes = types->NumFields();
// give variadic BIFs automatic pass
if ( ntypes == 1 && types->FieldDecl(0)->type->Tag() == TYPE_ANY )
return 1;
if ( el.length() < ntypes )
{
expr_list def_elements;
// Start from rightmost parameter, work backward to fill in missing
// arguments using &default expressions.
for ( int i = ntypes - 1; i >= el.length(); --i )
{
TypeDecl* td = types->FieldDecl(i);
Attr* def_attr = td->attrs ? td->attrs->FindAttr(ATTR_DEFAULT) : 0;
if ( ! def_attr )
{
types->Error("parameter mismatch", args);
return 0;
}
def_elements.push_front(def_attr->AttrExpr());
}
for ( const auto& elem : def_elements )
el.push_back(elem->Ref());
}
TypeList* tl = new TypeList();
for ( int i = 0; i < types->NumFields(); ++i )
tl->Append(types->FieldType(i)->Ref());
int rval = check_and_promote_exprs(args, tl);
Unref(tl);
return rval;
}
int check_and_promote_exprs_to_type(ListExpr*& elements, BroType* type)
{
expr_list& el = elements->Exprs();
if ( type->Tag() == TYPE_ANY )
return 1;
loop_over_list(el, i)
{
Expr* e = el[i];
if ( ! check_and_promote_expr(e, type) )
{
e->Error("type mismatch", type);
return 0;
}
if ( e != el[i] )
el.replace(i, e);
}
return 1;
}
val_list* eval_list(Frame* f, const ListExpr* l)
{
const expr_list& e = l->Exprs();
val_list* v = new val_list(e.length());
bool success = true;
for ( const auto& expr : e )
{
Val* ev = expr->Eval(f);
if ( ! ev )
{
success = false;
break;
}
v->push_back(ev);
}
if ( ! success )
{ // Failure.
for ( const auto& val : *v )
Unref(val);
delete v;
return 0;
}
else
return v;
}
int expr_greater(const Expr* e1, const Expr* e2)
{
return int(e1->Tag()) > int(e2->Tag());
}