mirror of
https://github.com/zeek/zeek.git
synced 2025-10-16 05:28:20 +00:00

This switches in from using strstr to use strnstr (implementation from FreeBSD on systems which do not bring their own implementation). It is especially likely that users come accross this when using the DATA_EVENT analyzer with files that contain binary data - the test uses exactly this case.
5447 lines
105 KiB
C++
5447 lines
105 KiB
C++
// See the file "COPYING" in the main distribution directory for copyright.
|
|
|
|
#include "bro-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 "RemoteSerializer.h"
|
|
#include "Net.h"
|
|
#include "Traverse.h"
|
|
#include "Trigger.h"
|
|
#include "IPAddr.h"
|
|
|
|
const char* expr_name(BroExprTag t)
|
|
{
|
|
static char errbuf[512];
|
|
|
|
static const char* expr_names[int(NUM_EXPRS)] = {
|
|
"name", "const",
|
|
"(*)",
|
|
"++", "--", "!", "+", "-",
|
|
"+", "-", "+=", "-=", "*", "/", "%", "&&", "||",
|
|
"<", "<=", "==", "!=", ">=", ">", "?:", "ref",
|
|
"=", "~", "[]", "$", "?$", "[=]",
|
|
"table()", "set()", "vector()",
|
|
"$=", "in", "<<>>",
|
|
"()", "event", "schedule",
|
|
"coerce", "record_coerce", "table_coerce",
|
|
"sizeof", "flatten"
|
|
};
|
|
|
|
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 */, Opcode /* op */)
|
|
{
|
|
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();
|
|
}
|
|
|
|
bool Expr::Serialize(SerialInfo* info) const
|
|
{
|
|
return SerialObj::Serialize(info);
|
|
}
|
|
|
|
Expr* Expr::Unserialize(UnserialInfo* info, BroExprTag want)
|
|
{
|
|
Expr* e = (Expr*) SerialObj::Unserialize(info, SER_EXPR);
|
|
|
|
if ( ! e )
|
|
return 0;
|
|
|
|
if ( want != EXPR_ANY && e->tag != want )
|
|
{
|
|
info->s->Error("wrong expression type");
|
|
Unref(e);
|
|
return 0;
|
|
}
|
|
|
|
return e;
|
|
}
|
|
|
|
bool Expr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_EXPR, BroObj);
|
|
|
|
if ( ! (SERIALIZE(char(tag)) && SERIALIZE(paren)) )
|
|
return false;
|
|
|
|
SERIALIZE_OPTIONAL(type);
|
|
return true;
|
|
}
|
|
|
|
bool Expr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(BroObj);
|
|
|
|
char c;
|
|
if ( ! (UNSERIALIZE(&c) && UNSERIALIZE(&paren)) )
|
|
return 0;
|
|
|
|
tag = BroExprTag(c);
|
|
|
|
BroType* t = 0;
|
|
UNSERIALIZE_OPTIONAL(t, BroType::Unserialize(info));
|
|
SetType(t);
|
|
return true;
|
|
}
|
|
|
|
|
|
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->NthElement(id->Offset());
|
|
|
|
else
|
|
// No frame - evaluating for Simplify() purposes
|
|
return 0;
|
|
|
|
if ( v )
|
|
return v->Ref();
|
|
else
|
|
{
|
|
Error("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");
|
|
|
|
return new RefExpr(this);
|
|
}
|
|
|
|
void NameExpr::Assign(Frame* f, Val* v, Opcode op)
|
|
{
|
|
if ( id->IsGlobal() )
|
|
id->SetVal(v, op);
|
|
else
|
|
f->SetElement(id->Offset(), 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());
|
|
}
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(NameExpr, SER_NAME_EXPR);
|
|
|
|
bool NameExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_NAME_EXPR, Expr);
|
|
|
|
// Write out just the name of the function if requested.
|
|
if ( info->globals_as_names && id->IsGlobal() )
|
|
return SERIALIZE('n') && SERIALIZE(id->Name()) &&
|
|
SERIALIZE(in_const_init);
|
|
else
|
|
return SERIALIZE('f') && id->Serialize(info) &&
|
|
SERIALIZE(in_const_init);
|
|
}
|
|
|
|
bool NameExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(Expr);
|
|
|
|
char type;
|
|
if ( ! UNSERIALIZE(&type) )
|
|
return false;
|
|
|
|
if ( type == 'n' )
|
|
{
|
|
const char* name;
|
|
if ( ! UNSERIALIZE_STR(&name, 0) )
|
|
return false;
|
|
|
|
id = global_scope()->Lookup(name);
|
|
if ( id )
|
|
::Ref(id);
|
|
else
|
|
reporter->Warning("configuration changed: unserialized unknown global name from persistent state");
|
|
|
|
delete [] name;
|
|
}
|
|
else
|
|
id = ID::Unserialize(info);
|
|
|
|
if ( ! id )
|
|
return false;
|
|
|
|
if ( ! UNSERIALIZE(&in_const_init) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(ConstExpr, SER_CONST_EXPR);
|
|
|
|
bool ConstExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_CONST_EXPR, Expr);
|
|
return val->Serialize(info);
|
|
}
|
|
|
|
bool ConstExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(Expr);
|
|
val = Val::Unserialize(info);
|
|
return val != 0;
|
|
}
|
|
|
|
|
|
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) )
|
|
{
|
|
VectorVal* v_op = v->AsVectorVal();
|
|
VectorVal* result = new VectorVal(Type()->AsVectorType());
|
|
|
|
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(")");
|
|
}
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(UnaryExpr, SER_UNARY_EXPR);
|
|
|
|
bool UnaryExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_UNARY_EXPR, Expr);
|
|
return op->Serialize(info);
|
|
}
|
|
|
|
bool UnaryExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(Expr);
|
|
op = Expr::Unserialize(info);
|
|
return op != 0;
|
|
}
|
|
|
|
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() )
|
|
{
|
|
Error("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 ( 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
|
|
Internal("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 \
|
|
Internal("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 )
|
|
reporter->ExprRuntimeError(this, "division by zero");
|
|
|
|
i3 = i1 / i2;
|
|
}
|
|
|
|
else if ( is_unsigned )
|
|
{
|
|
if ( u2 == 0 )
|
|
reporter->ExprRuntimeError(this, "division by zero");
|
|
|
|
u3 = u1 / u2;
|
|
}
|
|
else
|
|
{
|
|
if ( d2 == 0 )
|
|
reporter->ExprRuntimeError(this, "division by zero");
|
|
|
|
d3 = d1 / d2;
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case EXPR_MOD:
|
|
{
|
|
if ( is_integral )
|
|
{
|
|
if ( i2 == 0 )
|
|
reporter->ExprRuntimeError(this, "modulo by zero");
|
|
|
|
i3 = i1 % i2;
|
|
}
|
|
|
|
else if ( is_unsigned )
|
|
{
|
|
if ( u2 == 0 )
|
|
reporter->ExprRuntimeError(this, "modulo by zero");
|
|
|
|
u3 = u1 % u2;
|
|
}
|
|
|
|
else
|
|
Internal("bad type in BinaryExpr::Fold");
|
|
}
|
|
|
|
break;
|
|
|
|
case EXPR_AND: DO_INT_FOLD(&&); break;
|
|
case EXPR_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 new Val(u3, ret_type->Tag());
|
|
else
|
|
return new Val(i3, ret_type->Tag());
|
|
}
|
|
|
|
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 new Val(result, TYPE_BOOL);
|
|
}
|
|
|
|
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 new Val(result, TYPE_BOOL);
|
|
}
|
|
|
|
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 new Val(result, TYPE_BOOL);
|
|
}
|
|
|
|
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();
|
|
|
|
if ( IsVector(bt1) )
|
|
bt1 = op1->Type()->AsVectorType()->YieldType()->Tag();
|
|
if ( IsVector(bt2) )
|
|
bt2 = op2->Type()->AsVectorType()->YieldType()->Tag();
|
|
|
|
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));
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(BinaryExpr, SER_BINARY_EXPR);
|
|
|
|
bool BinaryExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_BINARY_EXPR, Expr);
|
|
return op1->Serialize(info) && op2->Serialize(info);
|
|
}
|
|
|
|
bool BinaryExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(Expr);
|
|
|
|
op1 = Expr::Unserialize(info);
|
|
if ( ! op1 )
|
|
return false;
|
|
|
|
op2 = Expr::Unserialize(info);
|
|
return op2 != 0;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(CloneExpr, SER_CLONE_EXPR);
|
|
|
|
bool CloneExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_CLONE_EXPR, UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool CloneExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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
|
|
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 )
|
|
Error("count underflow");
|
|
}
|
|
|
|
BroType* ret_type = Type();
|
|
if ( IsVector(ret_type->Tag()) )
|
|
ret_type = Type()->YieldType();
|
|
|
|
return new Val(k, ret_type->Tag());
|
|
}
|
|
|
|
|
|
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, OP_INCR);
|
|
}
|
|
else
|
|
v_vec->Assign(i, 0, OP_INCR);
|
|
}
|
|
op->Assign(f, v_vec, OP_INCR);
|
|
}
|
|
|
|
else
|
|
{
|
|
Val* old_v = v;
|
|
op->Assign(f, v = DoSingleEval(f, old_v), OP_INCR);
|
|
Unref(old_v);
|
|
}
|
|
|
|
return v->Ref();
|
|
}
|
|
|
|
int IncrExpr::IsPure() const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(IncrExpr, SER_INCR_EXPR);
|
|
|
|
bool IncrExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_INCR_EXPR, UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool IncrExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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 new Val(! v->InternalInt(), type->Tag());
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(NotExpr, SER_NOT_EXPR);
|
|
|
|
bool NotExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_NOT_EXPR, UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool NotExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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 new Val(v->CoerceToInt(), type->Tag());
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(PosExpr, SER_POS_EXPR);
|
|
|
|
bool PosExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_POS_EXPR, UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool PosExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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 new Val(- v->CoerceToInt(), TYPE_INT);
|
|
}
|
|
|
|
|
|
IMPLEMENT_SERIAL(NegExpr, SER_NEG_EXPR);
|
|
|
|
bool NegExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_NEG_EXPR, UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool NegExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
SizeExpr::SizeExpr(Expr* arg_op) : UnaryExpr(EXPR_SIZE, arg_op)
|
|
{
|
|
if ( IsError() )
|
|
return;
|
|
|
|
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();
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(SizeExpr, SER_SIZE_EXPR);
|
|
|
|
bool SizeExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_SIZE_EXPR, UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool SizeExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
|
|
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();
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(AddExpr, SER_ADD_EXPR);
|
|
|
|
bool AddExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_ADD_EXPR, BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool AddExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
AddToExpr::AddToExpr(Expr* arg_op1, Expr* arg_op2)
|
|
: BinaryExpr(EXPR_ADD_TO, 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
|
|
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;
|
|
}
|
|
|
|
Val* result = Fold(v1, v2);
|
|
Unref(v1);
|
|
Unref(v2);
|
|
|
|
if ( result )
|
|
{
|
|
op1->Assign(f, result);
|
|
return result->Ref();
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(AddToExpr, SER_ADD_TO_EXPR);
|
|
|
|
bool AddToExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_ADD_TO_EXPR, BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool AddToExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
SubExpr::SubExpr(Expr* arg_op1, Expr* arg_op2)
|
|
: BinaryExpr(EXPR_SUB, 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 ( 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 ( 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);
|
|
}
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(SubExpr, SER_SUB_EXPR);
|
|
|
|
bool SubExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_SUB_EXPR, BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool SubExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(RemoveFromExpr, SER_REMOVE_FROM_EXPR);
|
|
|
|
bool RemoveFromExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_REMOVE_FROM_EXPR, BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool RemoveFromExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(TimesExpr, SER_TIMES_EXPR);
|
|
|
|
bool TimesExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_TIMES_EXPR, BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool TimesExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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 mask;
|
|
if ( v2->Type()->Tag() == TYPE_COUNT )
|
|
mask = static_cast<uint32>(v2->InternalUnsigned());
|
|
else
|
|
mask = static_cast<uint32>(v2->InternalInt());
|
|
|
|
return new SubNetVal(v1->AsAddr(), mask);
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(DivideExpr, SER_DIVIDE_EXPR);
|
|
|
|
bool DivideExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_DIVIDE_EXPR, BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool DivideExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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");
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(ModExpr, SER_MOD_EXPR);
|
|
|
|
bool ModExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_MOD_EXPR, BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool ModExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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) )
|
|
SetType(new VectorType(base_type(TYPE_BOOL)));
|
|
else
|
|
SetType(base_type(TYPE_BOOL));
|
|
}
|
|
|
|
else if ( bt1 == TYPE_PATTERN && bt2 == bt1 )
|
|
SetType(base_type(TYPE_PATTERN));
|
|
|
|
else
|
|
ExprError("requires boolean operands");
|
|
}
|
|
|
|
Val* BoolExpr::DoSingleEval(Frame* f, Val* v1, Expr* op2) const
|
|
{
|
|
if ( ! v1 )
|
|
return 0;
|
|
|
|
if ( Type()->Tag() == TYPE_PATTERN )
|
|
{
|
|
Val* v2 = op2->Eval(f);
|
|
if ( ! v2 )
|
|
return 0;
|
|
|
|
RE_Matcher* re1 = v1->AsPattern();
|
|
RE_Matcher* re2 = v2->AsPattern();
|
|
|
|
RE_Matcher* res = tag == EXPR_AND ?
|
|
RE_Matcher_conjunction(re1, re2) :
|
|
RE_Matcher_disjunction(re1, re2);
|
|
|
|
return new PatternVal(res);
|
|
}
|
|
|
|
if ( tag == EXPR_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 and EXPR_AND or an EXPR_OR.
|
|
bool is_and = (tag == EXPR_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() )
|
|
{
|
|
Error("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) ?
|
|
(! op1->IsZero() && ! op2->IsZero()) :
|
|
(! op1->IsZero() || ! op2->IsZero());
|
|
|
|
result->Assign(i, new Val(local_result, TYPE_BOOL));
|
|
}
|
|
else
|
|
result->Assign(i, 0);
|
|
}
|
|
|
|
Unref(v1);
|
|
Unref(v2);
|
|
|
|
return result;
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(BoolExpr, SER_BOOL_EXPR);
|
|
|
|
bool BoolExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_BOOL_EXPR, BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool BoolExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
EqExpr::EqExpr(BroExprTag arg_tag, Expr* arg_op1, Expr* arg_op2)
|
|
: BinaryExpr(arg_tag, 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 ( 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(op1->Type(), op2->Type()) )
|
|
ExprError("illegal enum comparison");
|
|
break;
|
|
|
|
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 new Val(re->MatchExactly(s), TYPE_BOOL);
|
|
else
|
|
return new Val(! re->MatchExactly(s), TYPE_BOOL);
|
|
}
|
|
|
|
else
|
|
return BinaryExpr::Fold(v1, v2);
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(EqExpr, SER_EQ_EXPR);
|
|
|
|
bool EqExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_EQ_EXPR, BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool EqExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
RelExpr::RelExpr(BroExprTag arg_tag, Expr* arg_op1, Expr* arg_op2)
|
|
: BinaryExpr(arg_tag, 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 ( 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 ( 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;
|
|
}
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(RelExpr, SER_REL_EXPR);
|
|
|
|
bool RelExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_REL_EXPR, BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool RelExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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
|
|
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() )
|
|
{
|
|
Error("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);
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(CondExpr, SER_COND_EXPR);
|
|
|
|
bool CondExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_COND_EXPR, Expr);
|
|
return op1->Serialize(info) && op2->Serialize(info)
|
|
&& op3->Serialize(info);
|
|
}
|
|
|
|
bool CondExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(Expr);
|
|
|
|
op1 = Expr::Unserialize(info);
|
|
if ( ! op1 )
|
|
return false;
|
|
|
|
op2 = Expr::Unserialize(info);
|
|
if ( ! op2 )
|
|
return false;
|
|
|
|
op3 = Expr::Unserialize(info);
|
|
|
|
return op3 != 0;
|
|
}
|
|
|
|
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, Opcode opcode)
|
|
{
|
|
op->Assign(f, v, opcode);
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(RefExpr, SER_REF_EXPR);
|
|
|
|
bool RefExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_REF_EXPR, UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool RefExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
loop_over_list(*attrs, i)
|
|
attr_copy->append((*attrs)[i]);
|
|
}
|
|
|
|
if ( op1->Type()->IsSet() )
|
|
op2 = new SetConstructorExpr(op2->AsListExpr(), attr_copy);
|
|
else
|
|
op2 = new TableConstructorExpr(op2->AsListExpr(), attr_copy);
|
|
|
|
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());
|
|
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);
|
|
ListExpr* ctor_list = dynamic_cast<ListExpr*>(sce->Op());
|
|
attr_list* attr_copy = 0;
|
|
|
|
if ( sce->Attrs() )
|
|
{
|
|
attr_list* a = sce->Attrs()->Attrs();
|
|
attrs = new attr_list;
|
|
loop_over_list(*a, i)
|
|
attrs->append((*a)[i]);
|
|
}
|
|
|
|
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 )
|
|
{
|
|
Error("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 )
|
|
{
|
|
Error("not a record initializer", t);
|
|
return;
|
|
}
|
|
|
|
const RecordType* rt = t->AsRecordType();
|
|
int field = rt->FieldOffset(td.id);
|
|
|
|
if ( field < 0 )
|
|
{
|
|
Error("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 )
|
|
Error("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) )
|
|
Error("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;
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(AssignExpr, SER_ASSIGN_EXPR);
|
|
|
|
bool AssignExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_ASSIGN_EXPR, BinaryExpr);
|
|
SERIALIZE_OPTIONAL(val);
|
|
return SERIALIZE(is_init);
|
|
}
|
|
|
|
bool AssignExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(BinaryExpr);
|
|
UNSERIALIZE_OPTIONAL(val, Val::Unserialize(info));
|
|
return UNSERIALIZE(&is_init);
|
|
}
|
|
|
|
IndexExpr::IndexExpr(Expr* arg_op1, ListExpr* arg_op2, bool is_slice)
|
|
: BinaryExpr(EXPR_INDEX, arg_op1, arg_op2)
|
|
{
|
|
if ( IsError() )
|
|
return;
|
|
|
|
if ( is_slice )
|
|
{
|
|
if ( ! IsString(op1->Type()->Tag()) )
|
|
ExprError("slice notation indexing only supported for strings 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 )
|
|
SetError("not an index type");
|
|
|
|
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() )
|
|
{
|
|
Error("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:
|
|
v = v1->AsVectorVal()->Lookup(v2);
|
|
break;
|
|
|
|
case TYPE_TABLE:
|
|
v = v1->AsTableVal()->Lookup(v2);
|
|
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:
|
|
Error("type cannot be indexed");
|
|
break;
|
|
}
|
|
|
|
if ( v )
|
|
return v->Ref();
|
|
|
|
Error("no such index");
|
|
return 0;
|
|
}
|
|
|
|
void IndexExpr::Assign(Frame* f, Val* v, Opcode op)
|
|
{
|
|
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:
|
|
if ( ! v1->AsVectorVal()->Assign(v2, v, op) )
|
|
Internal("assignment failed");
|
|
break;
|
|
|
|
case TYPE_TABLE:
|
|
if ( ! v1->AsTableVal()->Assign(v2, v, op) )
|
|
Internal("assignment failed");
|
|
break;
|
|
|
|
case TYPE_STRING:
|
|
Internal("assignment via string index accessor not allowed");
|
|
break;
|
|
|
|
default:
|
|
Internal("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);
|
|
}
|
|
|
|
|
|
IMPLEMENT_SERIAL(IndexExpr, SER_INDEX_EXPR);
|
|
|
|
bool IndexExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_INDEX_EXPR, BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool IndexExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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 ( td->FindAttr(ATTR_DEPRECATED) )
|
|
reporter->Warning("deprecated (%s$%s)", rt->GetName().c_str(),
|
|
field_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
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, Opcode opcode)
|
|
{
|
|
if ( IsError() )
|
|
return;
|
|
|
|
if ( field < 0 )
|
|
ExprError("no such field in record");
|
|
|
|
Val* op_v = op->Eval(f);
|
|
if ( op_v )
|
|
{
|
|
RecordVal* r = op_v->AsRecordVal();
|
|
r->Assign(field, v, opcode);
|
|
Unref(r);
|
|
}
|
|
}
|
|
|
|
void FieldExpr::Delete(Frame* f)
|
|
{
|
|
Assign(f, 0, OP_ASSIGN_IDX);
|
|
}
|
|
|
|
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
|
|
{
|
|
reporter->ExprRuntimeError(this, "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);
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(FieldExpr, SER_FIELD_EXPR);
|
|
|
|
bool FieldExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_FIELD_EXPR, UnaryExpr);
|
|
|
|
if ( ! (SERIALIZE(field_name) && SERIALIZE(field) ) )
|
|
return false;
|
|
|
|
return td->Serialize(info);
|
|
}
|
|
|
|
bool FieldExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
|
|
if ( ! (UNSERIALIZE_STR(&field_name, 0) && UNSERIALIZE(&field) ) )
|
|
return false;
|
|
|
|
td = TypeDecl::Unserialize(info);
|
|
return td != 0;
|
|
}
|
|
|
|
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->FieldDecl(field)->FindAttr(ATTR_DEPRECATED) )
|
|
reporter->Warning("deprecated (%s?$%s)", rt->GetName().c_str(),
|
|
field_name);
|
|
|
|
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 new Val(0, TYPE_BOOL);
|
|
|
|
RecordVal* r = rec_to_look_at->Ref()->AsRecordVal();
|
|
Val* ret = new Val(r->Lookup(field) != 0, TYPE_BOOL);
|
|
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);
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(HasFieldExpr, SER_HAS_FIELD_EXPR);
|
|
|
|
bool HasFieldExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_HAS_FIELD_EXPR, UnaryExpr);
|
|
|
|
// Serialize former "bool is_attr" member first for backwards compatibility.
|
|
return SERIALIZE(false) && SERIALIZE(field_name) && SERIALIZE(field);
|
|
}
|
|
|
|
bool HasFieldExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
// Unserialize former "bool is_attr" member for backwards compatibility.
|
|
bool not_used;
|
|
return UNSERIALIZE(¬_used) && UNSERIALIZE_STR(&field_name, 0) && UNSERIALIZE(&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.
|
|
type_decl_list* record_types = new type_decl_list;
|
|
|
|
const expr_list& exprs = constructor_list->Exprs();
|
|
loop_over_list(exprs, i)
|
|
{
|
|
Expr* e = exprs[i];
|
|
|
|
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->append(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() )
|
|
Internal("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("]");
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(RecordConstructorExpr, SER_RECORD_CONSTRUCTOR_EXPR);
|
|
|
|
bool RecordConstructorExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_RECORD_CONSTRUCTOR_EXPR, UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool RecordConstructorExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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) : 0;
|
|
|
|
type_list* indices = type->AsTableType()->Indices()->Types();
|
|
const expr_list& cle = constructor_list->Exprs();
|
|
|
|
// check and promote all index expressions in ctor list
|
|
loop_over_list(cle, i)
|
|
{
|
|
if ( cle[i]->Tag() != EXPR_ASSIGN )
|
|
continue;
|
|
|
|
Expr* idx_expr = cle[i]->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();
|
|
|
|
loop_over_list(exprs, i)
|
|
exprs[i]->EvalIntoAggregate(type, aggr, 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();
|
|
|
|
loop_over_list(exprs, i)
|
|
exprs[i]->EvalIntoAggregate(t, tval, 0);
|
|
|
|
return tval;
|
|
}
|
|
|
|
void TableConstructorExpr::ExprDescribe(ODesc* d) const
|
|
{
|
|
d->Add("table(");
|
|
op->Describe(d);
|
|
d->Add(")");
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(TableConstructorExpr, SER_TABLE_CONSTRUCTOR_EXPR);
|
|
|
|
bool TableConstructorExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_TABLE_CONSTRUCTOR_EXPR, UnaryExpr);
|
|
SERIALIZE_OPTIONAL(attrs);
|
|
return true;
|
|
}
|
|
|
|
bool TableConstructorExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
UNSERIALIZE_OPTIONAL(attrs, Attributes::Unserialize(info));
|
|
return true;
|
|
}
|
|
|
|
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) : 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();
|
|
|
|
loop_over_list(exprs, i)
|
|
{
|
|
Val* element = exprs[i]->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();
|
|
|
|
loop_over_list(exprs, i)
|
|
{
|
|
Expr* e = exprs[i];
|
|
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(")");
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(SetConstructorExpr, SER_SET_CONSTRUCTOR_EXPR);
|
|
|
|
bool SetConstructorExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_SET_CONSTRUCTOR_EXPR, UnaryExpr);
|
|
SERIALIZE_OPTIONAL(attrs);
|
|
return true;
|
|
}
|
|
|
|
bool SetConstructorExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
UNSERIALIZE_OPTIONAL(attrs, Attributes::Unserialize(info));
|
|
return true;
|
|
}
|
|
|
|
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) )
|
|
{
|
|
Error(fmt("type mismatch at index %d", i), e);
|
|
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(")");
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(VectorConstructorExpr, SER_VECTOR_CONSTRUCTOR_EXPR);
|
|
|
|
bool VectorConstructorExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_VECTOR_CONSTRUCTOR_EXPR, UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool VectorConstructorExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(FieldAssignExpr, SER_FIELD_ASSIGN_EXPR);
|
|
|
|
bool FieldAssignExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_FIELD_ASSIGN_EXPR, UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool FieldAssignExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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 new Val(v->CoerceToInt(), TYPE_INT);
|
|
|
|
case TYPE_INTERNAL_UNSIGNED:
|
|
return new Val(v->CoerceToUnsigned(), TYPE_COUNT);
|
|
|
|
default:
|
|
Internal("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;
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(ArithCoerceExpr, SER_ARITH_COERCE_EXPR);
|
|
|
|
bool ArithCoerceExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_ARITH_COERCE_EXPR, UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool ArithCoerceExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
|
|
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) )
|
|
{
|
|
if ( sup_t_i->Tag() != TYPE_RECORD ||
|
|
sub_t_i->Tag() != TYPE_RECORD ||
|
|
! record_promotion_compatible(sup_t_i->AsRecordType(),
|
|
sub_t_i->AsRecordType()) )
|
|
{
|
|
char buf[512];
|
|
safe_snprintf(buf, sizeof(buf),
|
|
"type clash for field \"%s\"", sub_r->FieldName(i));
|
|
Error(buf, 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) )
|
|
{
|
|
char buf[512];
|
|
safe_snprintf(buf, sizeof(buf),
|
|
"non-optional field \"%s\" missing",
|
|
t_r->FieldName(i));
|
|
Error(buf);
|
|
SetError();
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( t_r->FieldDecl(i)->FindAttr(ATTR_DEPRECATED) )
|
|
reporter->Warning("deprecated (%s$%s)",
|
|
t_r->GetName().c_str(),
|
|
t_r->FieldName(i));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(RecordCoerceExpr, SER_RECORD_COERCE_EXPR);
|
|
|
|
bool RecordCoerceExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_RECORD_COERCE_EXPR, UnaryExpr);
|
|
|
|
if ( ! SERIALIZE(map_size) )
|
|
return false;
|
|
|
|
for ( int i = 0; i < map_size; ++i )
|
|
if ( ! SERIALIZE(map[i]) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool RecordCoerceExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
|
|
if ( ! UNSERIALIZE(&map_size) )
|
|
return false;
|
|
|
|
map = new int[map_size];
|
|
|
|
for ( int i = 0; i < map_size; ++i )
|
|
if ( ! UNSERIALIZE(&map[i]) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
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 )
|
|
Internal("coercion of non-empty table/set");
|
|
|
|
return new TableVal(Type()->AsTableType(), tv->Attrs());
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(TableCoerceExpr, SER_TABLE_COERCE_EXPR);
|
|
|
|
bool TableCoerceExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_TABLE_COERCE_EXPR, UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool TableCoerceExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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 )
|
|
Internal("coercion of non-empty vector");
|
|
|
|
return new VectorVal(Type()->Ref()->AsVectorType());
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(VectorCoerceExpr, SER_VECTOR_COERCE_EXPR);
|
|
|
|
bool VectorCoerceExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_VECTOR_COERCE_EXPR, UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool VectorCoerceExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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
|
|
reporter->ExprRuntimeError(this, "missing field value");
|
|
}
|
|
|
|
return l;
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(FlattenExpr, SER_FLATTEN_EXPR);
|
|
|
|
bool FlattenExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_FLATTEN_EXPR, UnaryExpr);
|
|
return SERIALIZE(num_fields);
|
|
}
|
|
|
|
bool FlattenExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(UnaryExpr);
|
|
return UNSERIALIZE(&num_fields);
|
|
}
|
|
|
|
ScheduleTimer::ScheduleTimer(EventHandlerPtr arg_event, val_list* arg_args,
|
|
double t, TimerMgr* arg_tmgr)
|
|
: Timer(t, TIMER_SCHEDULE)
|
|
{
|
|
event = arg_event;
|
|
args = arg_args;
|
|
tmgr = arg_tmgr;
|
|
}
|
|
|
|
ScheduleTimer::~ScheduleTimer()
|
|
{
|
|
}
|
|
|
|
void ScheduleTimer::Dispatch(double /* t */, int /* is_expire */)
|
|
{
|
|
mgr.QueueEvent(event, 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);
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(ScheduleExpr, SER_SCHEDULE_EXPR);
|
|
|
|
bool ScheduleExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_SCHEDULE_EXPR, Expr);
|
|
return when->Serialize(info) && event->Serialize(info);
|
|
}
|
|
|
|
bool ScheduleExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(Expr);
|
|
|
|
when = Expr::Unserialize(info);
|
|
if ( ! when )
|
|
return false;
|
|
|
|
event = (EventExpr*) Expr::Unserialize(info, EXPR_EVENT);
|
|
return event != 0;
|
|
}
|
|
|
|
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 new Val(re->MatchAnywhere(s) != 0, TYPE_BOOL);
|
|
}
|
|
|
|
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 new Val(strstr_n(s2->Len(), s2->Bytes(), s1->Len(), reinterpret_cast<const unsigned char*>(s1->CheckString())) != -1, TYPE_BOOL);
|
|
}
|
|
|
|
if ( v1->Type()->Tag() == TYPE_ADDR &&
|
|
v2->Type()->Tag() == TYPE_SUBNET )
|
|
return new Val(v2->AsSubNetVal()->Contains(v1->AsAddr()), TYPE_BOOL);
|
|
|
|
Val* res;
|
|
|
|
if ( is_vector(v2) )
|
|
res = v2->AsVectorVal()->Lookup(v1);
|
|
else
|
|
res = v2->AsTableVal()->Lookup(v1, false);
|
|
|
|
if ( res )
|
|
return new Val(1, TYPE_BOOL);
|
|
else
|
|
return new Val(0, TYPE_BOOL);
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(InExpr, SER_IN_EXPR);
|
|
|
|
bool InExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_IN_EXPR, BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
bool InExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(BinaryExpr);
|
|
return true;
|
|
}
|
|
|
|
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 = 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();
|
|
calling_expr = this;
|
|
const CallExpr* current_call = f ? f->GetCall() : 0;
|
|
|
|
if ( f )
|
|
f->SetCall(this);
|
|
|
|
ret = func->Call(v, f); // No try/catch here; we pass exceptions upstream.
|
|
|
|
if ( f )
|
|
f->SetCall(current_call);
|
|
|
|
// Don't Unref() the arguments, as Func::Call already did that.
|
|
delete v;
|
|
|
|
calling_expr = 0;
|
|
}
|
|
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);
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(CallExpr, SER_CALL_EXPR);
|
|
|
|
bool CallExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_CALL_EXPR, Expr);
|
|
return func->Serialize(info) && args->Serialize(info);
|
|
}
|
|
|
|
bool CallExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(Expr);
|
|
|
|
func = Expr::Unserialize(info);
|
|
if ( ! func )
|
|
return false;
|
|
|
|
args = (ListExpr*) Expr::Unserialize(info, EXPR_LIST);
|
|
return args != 0;
|
|
}
|
|
|
|
EventExpr::EventExpr(const char* arg_name, ListExpr* arg_args)
|
|
: Expr(EXPR_EVENT)
|
|
{
|
|
name = arg_name;
|
|
args = arg_args;
|
|
|
|
EventHandler* h = event_registry->Lookup(name.c_str());
|
|
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, 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);
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(EventExpr, SER_EVENT_EXPR);
|
|
|
|
bool EventExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_EVENT_EXPR, Expr);
|
|
|
|
if ( ! handler->Serialize(info) )
|
|
return false;
|
|
|
|
return SERIALIZE(name) && args->Serialize(info);
|
|
}
|
|
|
|
bool EventExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(Expr);
|
|
|
|
EventHandler* h = EventHandler::Unserialize(info);
|
|
if ( ! h )
|
|
return false;
|
|
|
|
handler = h;
|
|
|
|
if ( ! UNSERIALIZE(&name) )
|
|
return false;
|
|
|
|
args = (ListExpr*) Expr::Unserialize(info, EXPR_LIST);
|
|
return args;
|
|
}
|
|
|
|
ListExpr::ListExpr() : Expr(EXPR_LIST)
|
|
{
|
|
SetType(new TypeList());
|
|
}
|
|
|
|
ListExpr::ListExpr(Expr* e) : Expr(EXPR_LIST)
|
|
{
|
|
SetType(new TypeList());
|
|
Append(e);
|
|
}
|
|
|
|
ListExpr::~ListExpr()
|
|
{
|
|
loop_over_list(exprs, i)
|
|
Unref(exprs[i]);
|
|
}
|
|
|
|
void ListExpr::Append(Expr* e)
|
|
{
|
|
exprs.append(e);
|
|
((TypeList*) type)->Append(e->Type()->Ref());
|
|
}
|
|
|
|
int ListExpr::IsPure() const
|
|
{
|
|
loop_over_list(exprs, i)
|
|
if ( ! exprs[i]->IsPure() )
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int ListExpr::AllConst() const
|
|
{
|
|
loop_over_list(exprs, i)
|
|
if ( ! exprs[i]->IsConst() )
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
Val* ListExpr::Eval(Frame* f) const
|
|
{
|
|
ListVal* v = new ListVal(TYPE_ANY);
|
|
|
|
loop_over_list(exprs, i)
|
|
{
|
|
Val* ev = exprs[i]->Eval(f);
|
|
if ( ! ev )
|
|
{
|
|
Error("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;
|
|
loop_over_list(exprs, i)
|
|
{
|
|
TypeDecl* td = new TypeDecl(0, 0);
|
|
if ( ! exprs[i]->IsRecordElement(td) )
|
|
{
|
|
exprs[i]->Error("record element expected");
|
|
delete td;
|
|
delete types;
|
|
return 0;
|
|
}
|
|
|
|
types->append(td);
|
|
}
|
|
|
|
|
|
return new RecordType(types);
|
|
}
|
|
|
|
else
|
|
{
|
|
TypeList* tl = new TypeList();
|
|
loop_over_list(exprs, i)
|
|
{
|
|
Expr* e = exprs[i];
|
|
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.
|
|
loop_over_list(exprs, i)
|
|
{
|
|
Expr* e = exprs[i];
|
|
|
|
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();
|
|
|
|
loop_over_list(exprs, i)
|
|
{
|
|
Val* element;
|
|
|
|
if ( exprs[i]->Type()->IsSet() )
|
|
// A set to flatten.
|
|
element = exprs[i]->Eval(0);
|
|
else if ( exprs[i]->Type()->Tag() == TYPE_LIST )
|
|
element = exprs[i]->InitVal(it, 0);
|
|
else
|
|
element = exprs[i]->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 ( exprs[i]->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()
|
|
{
|
|
loop_over_list(exprs, i)
|
|
if ( exprs[i]->Tag() != EXPR_NAME )
|
|
ExprError("can only assign to list of identifiers");
|
|
|
|
return new RefExpr(this);
|
|
}
|
|
|
|
void ListExpr::Assign(Frame* f, Val* v, Opcode op)
|
|
{
|
|
ListVal* lv = v->AsListVal();
|
|
|
|
if ( exprs.length() != lv->Vals()->length() )
|
|
ExprError("mismatch in list lengths");
|
|
|
|
loop_over_list(exprs, i)
|
|
exprs[i]->Assign(f, (*lv->Vals())[i]->Ref(), op);
|
|
|
|
Unref(lv);
|
|
}
|
|
|
|
TraversalCode ListExpr::Traverse(TraversalCallback* cb) const
|
|
{
|
|
TraversalCode tc = cb->PreExpr(this);
|
|
HANDLE_TC_EXPR_PRE(tc);
|
|
|
|
loop_over_list(exprs, i)
|
|
{
|
|
tc = exprs[i]->Traverse(cb);
|
|
HANDLE_TC_EXPR_PRE(tc);
|
|
}
|
|
|
|
tc = cb->PostExpr(this);
|
|
HANDLE_TC_EXPR_POST(tc);
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(ListExpr, SER_LIST_EXPR);
|
|
|
|
bool ListExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_LIST_EXPR, Expr);
|
|
|
|
if ( ! SERIALIZE(exprs.length()) )
|
|
return false;
|
|
|
|
loop_over_list(exprs, i)
|
|
if ( ! exprs[i]->Serialize(info) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ListExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(Expr);
|
|
|
|
int len;
|
|
if ( ! UNSERIALIZE(&len) )
|
|
return false;
|
|
|
|
while ( len-- )
|
|
{
|
|
Expr* e = Expr::Unserialize(info);
|
|
if ( ! e )
|
|
return false;
|
|
|
|
exprs.append(e);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
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 ( int i = 0; i < inits.length(); ++i )
|
|
{
|
|
if ( inits[i]->Type()->Tag() == TYPE_RECORD )
|
|
{
|
|
RecordType* t = inits[i]->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(inits[i], field_name);
|
|
Append(get_assign_expr(fe_lhs->Ref(), fe_rhs->Ref(), is_init));
|
|
}
|
|
}
|
|
}
|
|
|
|
else if ( inits[i]->Tag() == EXPR_FIELD_ASSIGN )
|
|
{
|
|
FieldAssignExpr* rf = (FieldAssignExpr*) inits[i];
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
IMPLEMENT_SERIAL(RecordAssignExpr, SER_RECORD_ASSIGN_EXPR);
|
|
|
|
bool RecordAssignExpr::DoSerialize(SerialInfo* info) const
|
|
{
|
|
DO_SERIALIZE(SER_RECORD_ASSIGN_EXPR, ListExpr);
|
|
return true;
|
|
}
|
|
|
|
bool RecordAssignExpr::DoUnserialize(UnserialInfo* info)
|
|
{
|
|
DO_UNSERIALIZE(ListExpr);
|
|
return true;
|
|
}
|
|
|
|
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
|
|
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.insert(def_attr->AttrExpr());
|
|
}
|
|
|
|
loop_over_list(def_elements, i)
|
|
el.append(def_elements[i]->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());
|
|
|
|
loop_over_list(e, i)
|
|
{
|
|
Val* ev = e[i]->Eval(f);
|
|
if ( ! ev )
|
|
break;
|
|
v->append(ev);
|
|
}
|
|
|
|
if ( i < e.length() )
|
|
{ // Failure.
|
|
loop_over_list(*v, j)
|
|
Unref((*v)[j]);
|
|
delete v;
|
|
return 0;
|
|
}
|
|
|
|
else
|
|
return v;
|
|
}
|
|
|
|
int expr_greater(const Expr* e1, const Expr* e2)
|
|
{
|
|
return int(e1->Tag()) > int(e2->Tag());
|
|
}
|
|
|
|
static Expr* make_constant(BroType* t, double d)
|
|
{
|
|
Val* v = 0;
|
|
switch ( t->InternalType() ) {
|
|
case TYPE_INTERNAL_INT: v = new Val(bro_int_t(d), t->Tag()); break;
|
|
case TYPE_INTERNAL_UNSIGNED: v = new Val(bro_uint_t(d), t->Tag()); break;
|
|
case TYPE_INTERNAL_DOUBLE: v = new Val(double(d), t->Tag()); break;
|
|
|
|
default:
|
|
reporter->InternalError("bad type in make_constant()");
|
|
}
|
|
|
|
return new ConstExpr(v);
|
|
}
|
|
|
|
Expr* make_zero(BroType* t)
|
|
{
|
|
return make_constant(t, 0.0);
|
|
}
|
|
|
|
Expr* make_one(BroType* t)
|
|
{
|
|
return make_constant(t, 1.0);
|
|
}
|