// See the file "COPYING" in the main distribution directory for copyright. #include "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); } Expr* NameExpr::Simplify(SimplifyType simp_type) { if ( simp_type != SIMPLIFY_LHS && id->IsConst() ) { Val* v = Eval(0); if ( v ) return new ConstExpr(v); } return this; } 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); } Expr* ConstExpr::Simplify(SimplifyType /* simp_type */) { return this; } 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); } Expr* UnaryExpr::Simplify(SimplifyType simp_type) { if ( IsError() ) return this; op = simplify_expr(op, simp_type); Canonicize(); return DoSimplify(); } 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); } Expr* UnaryExpr::DoSimplify() { return this; } 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); } Expr* BinaryExpr::Simplify(SimplifyType /* simp_type */) { if ( IsError() ) return this; SimplifyOps(); if ( BothConst() ) return new ConstExpr(Fold(op1->ExprVal(), op2->ExprVal())); else return DoSimplify(); } 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); } Expr* BinaryExpr::DoSimplify() { return this; } void BinaryExpr::ExprDescribe(ODesc* d) const { op1->Describe(d); d->SP(); if ( d->IsReadable() ) d->AddSP(expr_name(Tag())); op2->Describe(d); } void BinaryExpr::SimplifyOps() { op1 = simplify_expr(op1, SIMPLIFY_GENERAL); op2 = simplify_expr(op2, SIMPLIFY_GENERAL); Canonicize(); } 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 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)); } Expr* NotExpr::DoSimplify() { op = simplify_expr(op, SIMPLIFY_GENERAL); Canonicize(); if ( op->Tag() == EXPR_NOT ) // !!x == x return ((NotExpr*) op)->Op()->Ref(); if ( op->IsConst() ) return new ConstExpr(Fold(op->ExprVal())); return this; } 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); } Expr* PosExpr::DoSimplify() { op = simplify_expr(op, SIMPLIFY_GENERAL); Canonicize(); TypeTag t = op->Type()->Tag(); if ( t == TYPE_DOUBLE || t == TYPE_INTERVAL || t == TYPE_INT ) return op->Ref(); if ( op->IsConst() && ! is_vector(op->ExprVal()) ) return new ConstExpr(Fold(op->ExprVal())); return this; } 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); } Expr* NegExpr::DoSimplify() { op = simplify_expr(op, SIMPLIFY_GENERAL); Canonicize(); if ( op->Tag() == EXPR_NEGATE ) // -(-x) == x return ((NegExpr*) op)->Op()->Ref(); if ( op->IsConst() && ! is_vector(op->ExprVal()) ) return new ConstExpr(Fold(op->ExprVal())); if ( op->Tag() == EXPR_SUB ) { // -(a-b) == b-a SubExpr* s = (SubExpr*) op; return new SubExpr(s->Op2()->Ref(), s->Op1()->Ref()); } return this; } 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); } } Expr* AddExpr::DoSimplify() { // If there's a constant, then it's in op1, since Canonicize() // makes sure of that. if ( op1->IsZero() ) return op2->Ref(); else if ( op1->Tag() == EXPR_NEGATE ) // (-a)+b = b-a return new AddExpr(op2->Ref(), ((NegExpr*) op1)->Op()->Ref()); else if ( op2->Tag() == EXPR_NEGATE ) // a+(-b) == a-b return new SubExpr(op1->Ref(), ((NegExpr*) op2)->Op()->Ref()); return this; } 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); } } Expr* SubExpr::DoSimplify() { if ( op1->IsZero() ) return new NegExpr(op2->Ref()); else if ( op2->IsZero() ) return op1->Ref(); else if ( op2->Tag() == EXPR_NEGATE ) // a-(-b) = a+b return new AddExpr(op1->Ref(), ((NegExpr*) op2)->Op()->Ref()); return this; } 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"); } Expr* TimesExpr::DoSimplify() { // If there's a constant, then it's in op1, since Canonicize() // makes sure of that. if ( op1->IsConst() ) { if ( op1->IsZero() ) { if ( IsVector(op2->Type()->Tag()) ) return this; else return make_zero(type); } else if ( op1->IsOne() ) return op2->Ref(); } return this; } 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(v2->InternalUnsigned()); else mask = static_cast(v2->InternalInt()); return new SubNetVal(v1->AsAddr(), mask); } Expr* DivideExpr::DoSimplify() { if ( IsError() ) return this; if ( op1->Type()->Tag() == TYPE_ADDR ) return this; if ( is_vector(op1) || is_vector(op2) ) return this; if ( op2->IsConst() ) { if ( op2->IsOne() ) return op1->Ref(); else if ( op2->IsZero() ) Error("zero divisor"); } else if ( same_expr(op1, op2) ) return make_one(type); return this; } 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"); } Expr* ModExpr::DoSimplify() { if ( IsError() ) return this; TypeTag bt1 = op1->Type()->Tag(); TypeTag bt2 = op2->Type()->Tag(); if ( IsVector(bt1) || IsVector(bt2) ) return this; if ( op2->IsConst() ) { if ( op2->IsOne() ) return make_zero(type); else if ( op2->IsZero() ) Error("zero modulus"); } else if ( same_expr(op1, op2) ) return make_zero(type); return this; } 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; } Expr* BoolExpr::DoSimplify() { if ( op1->IsConst() && ! is_vector(op1) ) { if ( op1->IsZero() ) // F && x or F || x return (tag == EXPR_AND) ? make_zero(type) : op2->Ref(); else // T && x or T || x return (tag == EXPR_AND) ? op2->Ref() : make_one(type); } else if ( op2->IsConst() && ! is_vector(op2) ) { if ( op1->IsZero() ) // x && F or x || F return (tag == EXPR_AND) ? make_zero(type) : op1->Ref(); else // x && T or x || T return (tag == EXPR_AND) ? op1->Ref() : make_one(type); } else if ( same_expr(op1, op2) ) { Warn("redundant boolean operation"); return op1->Ref(); } return this; } 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(); } Expr* EqExpr::DoSimplify() { if ( same_expr(op1, op2) && ! is_vector(op1) ) { if ( ! optimize ) Warn("redundant comparison"); if ( tag == EXPR_EQ ) return make_one(type); else return make_zero(type); } return this; } 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"); } Expr* RelExpr::DoSimplify() { if ( same_expr(op1, op2) ) { Warn("redundant comparison"); // Here we use the fact that the canonical form of // a RelExpr only uses EXPR_LE or EXPR_LT. if ( tag == EXPR_LE ) return make_one(type); else return make_zero(type); } return this; } 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); } Expr* CondExpr::Simplify(SimplifyType /* simp_type */) { op1 = simplify_expr(op1, SIMPLIFY_GENERAL); op2 = simplify_expr(op2, SIMPLIFY_GENERAL); op3 = simplify_expr(op3, SIMPLIFY_GENERAL); if ( op1->IsConst() && ! is_vector(op1) ) { Val* v = op1->ExprVal(); return (v->IsZero() ? op3 : op2)->Ref(); } if ( op1->Tag() == EXPR_NOT ) return new CondExpr(((NotExpr*) op1)->Op()->Ref(), op3->Ref(), op2->Ref()); return this; } 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()) ) { 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; } Expr* AssignExpr::Simplify(SimplifyType /* simp_type */) { op1 = simplify_expr(op1, SIMPLIFY_LHS); op2 = simplify_expr(op2, SIMPLIFY_GENERAL); return this; } 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); } Expr* IndexExpr::Simplify(SimplifyType simp_type) { op1 = simplify_expr(op1, simp_type); op2 = simplify_expr(op2, SIMPLIFY_GENERAL); return 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); } Expr* FieldExpr::Simplify(SimplifyType simp_type) { op = simplify_expr(op, simp_type); return 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(""); 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(""); 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"); } Expr* ArithCoerceExpr::DoSimplify() { if ( is_vector(op) ) return this; InternalTypeTag my_int = type->InternalType(); InternalTypeTag op_int = op->Type()->InternalType(); if ( my_int == TYPE_INTERNAL_UNSIGNED ) my_int = TYPE_INTERNAL_INT; if ( op_int == TYPE_INTERNAL_UNSIGNED ) op_int = TYPE_INTERNAL_INT; if ( my_int == op_int ) return op->Ref(); if ( op->IsConst() ) { if ( my_int == TYPE_INTERNAL_INT ) { if ( op_int != TYPE_INTERNAL_DOUBLE ) Internal("bad coercion in CoerceExpr::DoSimplify"); double d = op->ExprVal()->InternalDouble(); bro_int_t i = bro_int_t(d); if ( i < 0 && type->InternalType() == TYPE_INTERNAL_UNSIGNED ) Warn("coercion produces negative count value"); if ( d != double(i) ) Warn("coercion loses precision"); return new ConstExpr(new Val(i, type->Tag())); } if ( my_int == TYPE_INTERNAL_DOUBLE ) { if ( op_int == TYPE_INTERNAL_INT ) { bro_int_t i = op->ExprVal()->InternalInt(); double d = double(i); if ( i != bro_int_t(d) ) Warn("coercion loses precision"); return new ConstExpr(new Val(d, type->Tag())); } if ( op_int == TYPE_INTERNAL_UNSIGNED ) { bro_uint_t u = op->ExprVal()->InternalUnsigned(); double d = double(u); if ( u != (bro_uint_t) (d) ) Warn("coercion loses precision"); return new ConstExpr(new Val(d, type->Tag())); } } Internal("bad coercion in CoerceExpr::DoSimplify"); } return this; } 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; } 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; } Expr* ScheduleExpr::Simplify(SimplifyType simp_type) { when = when->Simplify(simp_type); Expr* generic_event = event->Simplify(simp_type); if ( ! generic_event ) return 0; if ( generic_event->Tag() != EXPR_CALL ) Internal("bad event type in ScheduleExpr::Simplify"); event = (EventExpr*) generic_event; return this; } 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: in // in set[subnet] // 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 - either roll our own, to deal with // NULs, and/or Boyer-Moore if done repeatedly. return new Val(strstr(s2->CheckString(), s1->CheckString()) != 0, 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; } Expr* CallExpr::Simplify(SimplifyType /* simp_type */) { if ( IsError() ) return this; func = simplify_expr(func, SIMPLIFY_GENERAL); args = simplify_expr_list(args, SIMPLIFY_GENERAL); if ( IsPure() ) return new ConstExpr(Eval(0)); else return this; } 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); } Expr* EventExpr::Simplify(SimplifyType /* simp_type */) { if ( ! IsError() ) args = simplify_expr_list(args, SIMPLIFY_GENERAL); return this; } 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; } Expr* ListExpr::Simplify(SimplifyType /* simp_type */) { loop_over_list(exprs, i) exprs.replace(i, simplify_expr(exprs[i], SIMPLIFY_GENERAL)); // Note that we do *not* simplify a list with one element // to just that element. The assumption that simplify_expr(ListExpr*) // returns a ListExpr* is widespread. return this; } 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; } Expr* simplify_expr(Expr* e, SimplifyType simp_type) { if ( ! e ) return 0; for ( Expr* s = e->Simplify(simp_type); s != e; s = e->Simplify(simp_type) ) { Unref(e); e = s; } return e; } ListExpr* simplify_expr_list(ListExpr* l, SimplifyType simp_type) { return (ListExpr*) simplify_expr(l, simp_type); } 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 same_expr(const Expr* e1, const Expr* e2) { if ( e1 == e2 ) return 1; if ( e1->Tag() != e2->Tag() || ! same_type(e1->Type(), e2->Type()) ) return 0; if ( e1->IsError() || e2->IsError() ) return 0; switch ( e1->Tag() ) { case EXPR_NAME: { const NameExpr* n1 = (NameExpr*) e1; const NameExpr* n2 = (NameExpr*) e2; return n1->Id() == n2->Id(); } case EXPR_CONST: { const ConstExpr* c1 = (ConstExpr*) e1; const ConstExpr* c2 = (ConstExpr*) e2; return same_val(c1->Value(), c2->Value()); } case EXPR_INCR: case EXPR_DECR: case EXPR_NOT: case EXPR_NEGATE: case EXPR_POSITIVE: case EXPR_REF: case EXPR_RECORD_CONSTRUCTOR: case EXPR_TABLE_CONSTRUCTOR: case EXPR_SET_CONSTRUCTOR: case EXPR_VECTOR_CONSTRUCTOR: case EXPR_FIELD_ASSIGN: case EXPR_ARITH_COERCE: case EXPR_RECORD_COERCE: case EXPR_TABLE_COERCE: case EXPR_FLATTEN: { const UnaryExpr* u1 = (UnaryExpr*) e1; const UnaryExpr* u2 = (UnaryExpr*) e2; return same_expr(u1->Op(), u2->Op()); } case EXPR_FIELD: { const FieldExpr* f1 = (FieldExpr*) e1; const FieldExpr* f2 = (FieldExpr*) e2; return same_expr(f1->Op(), f2->Op()) && f1->Field() == f2->Field(); } case EXPR_SCHEDULE: { const ScheduleExpr* s1 = (ScheduleExpr*) e1; const ScheduleExpr* s2 = (ScheduleExpr*) e2; return same_expr(s1->When(), s2->When()) && same_expr(s1->Event(), s2->Event()); } case EXPR_ADD: case EXPR_ADD_TO: case EXPR_SUB: case EXPR_REMOVE_FROM: case EXPR_TIMES: case EXPR_DIVIDE: case EXPR_MOD: case EXPR_AND: case EXPR_OR: case EXPR_LT: case EXPR_LE: case EXPR_EQ: case EXPR_NE: case EXPR_GE: case EXPR_GT: case EXPR_ASSIGN: case EXPR_MATCH: case EXPR_INDEX: case EXPR_IN: { const BinaryExpr* b1 = (BinaryExpr*) e1; const BinaryExpr* b2 = (BinaryExpr*) e2; return same_expr(b1->Op1(), b2->Op1()) && same_expr(b1->Op2(), b2->Op2()); } case EXPR_LIST: { const ListExpr* l1 = (ListExpr*) e1; const ListExpr* l2 = (ListExpr*) e2; const expr_list& le1 = l1->Exprs(); const expr_list& le2 = l2->Exprs(); if ( le1.length() != le2.length() ) return 0; loop_over_list(le1, i) if ( ! same_expr(le1[i], le2[i]) ) return 0; return 1; } case EXPR_CALL: { const CallExpr* c1 = (CallExpr*) e1; const CallExpr* c2 = (CallExpr*) e2; return same_expr(c1->Func(), c2->Func()) && c1->IsPure() && same_expr(c1->Args(), c2->Args()); } default: reporter->InternalError("bad tag in same_expr()"); } return 0; } 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); }