diff --git a/src/Expr.cc b/src/Expr.cc index d384bb27e0..0de68b1f46 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -2497,12 +2497,7 @@ AssignExpr::AssignExpr(Expr* arg_op1, Expr* arg_op2, int arg_is_init, bool AssignExpr::TypeCheck() { 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_LIST && bt2 == TYPE_ANY ) // This is ok because we cannot explicitly declare lists on @@ -2531,6 +2526,13 @@ bool AssignExpr::TypeCheck() return true; } + if ( bt1 == TYPE_VECTOR && bt2 == bt1 && + op2->Type()->AsVectorType()->IsUnspecifiedVector() ) + { + op2 = new VectorCoerceExpr(op2, op1->Type()->AsVectorType()); + return true; + } + if ( op1->Type()->Tag() == TYPE_RECORD && op2->Type()->Tag() == TYPE_RECORD ) { @@ -3506,6 +3508,13 @@ VectorConstructorExpr::VectorConstructorExpr(ListExpr* constructor_list) if ( IsError() ) return; + if ( constructor_list->Exprs().length() == 0 ) + { + // vector(). + SetType(new ::VectorType(base_type(TYPE_ANY))); + return; + } + BroType* t = merge_type_list(constructor_list); if ( t ) { @@ -4122,6 +4131,50 @@ bool TableCoerceExpr::DoUnserialize(UnserialInfo* info) 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) { @@ -5337,6 +5390,13 @@ int check_and_promote_expr(Expr*& e, BroType* t) 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; } diff --git a/src/Expr.h b/src/Expr.h index 9c338a0f8a..933c42daa2 100644 --- a/src/Expr.h +++ b/src/Expr.h @@ -40,7 +40,7 @@ typedef enum { EXPR_CALL, EXPR_EVENT, EXPR_SCHEDULE, - EXPR_ARITH_COERCE, EXPR_RECORD_COERCE, EXPR_TABLE_COERCE, + EXPR_ARITH_COERCE, EXPR_RECORD_COERCE, EXPR_TABLE_COERCE, EXPR_VECTOR_COERCE, EXPR_SIZE, EXPR_FLATTEN, #define NUM_EXPRS (int(EXPR_FLATTEN) + 1) @@ -895,6 +895,20 @@ protected: DECLARE_SERIAL(TableCoerceExpr); }; +class VectorCoerceExpr : public UnaryExpr { +public: + VectorCoerceExpr(Expr* op, VectorType* v); + ~VectorCoerceExpr(); + +protected: + friend class Expr; + VectorCoerceExpr() { } + + Val* Fold(Val* v) const; + + DECLARE_SERIAL(VectorCoerceExpr); +}; + // An internal operator for flattening array indices that are records // into a list of individual values. class FlattenExpr : public UnaryExpr { diff --git a/src/SerialTypes.h b/src/SerialTypes.h index a33b026fae..4f9ab4585b 100644 --- a/src/SerialTypes.h +++ b/src/SerialTypes.h @@ -146,6 +146,7 @@ SERIAL_EXPR(TABLE_CONSTRUCTOR_EXPR, 40) SERIAL_EXPR(SET_CONSTRUCTOR_EXPR, 41) SERIAL_EXPR(VECTOR_CONSTRUCTOR_EXPR, 42) SERIAL_EXPR(TABLE_COERCE_EXPR, 43) +SERIAL_EXPR(VECTOR_COERCE_EXPR, 44) #define SERIAL_STMT(name, val) SERIAL_CONST(name, val, STMT) SERIAL_STMT(STMT, 1) diff --git a/src/Type.cc b/src/Type.cc index 61d8b6a8dd..4bcd31cc4d 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -1290,6 +1290,11 @@ int VectorType::MatchesIndex(ListExpr*& index) const MATCHES_INDEX_SCALAR : DOES_NOT_MATCH_INDEX; } +bool VectorType::IsUnspecifiedVector() const + { + return yield_type->Tag() == TYPE_ANY; + } + IMPLEMENT_SERIAL(VectorType, SER_VECTOR_TYPE); bool VectorType::DoSerialize(SerialInfo* info) const @@ -1651,6 +1656,7 @@ BroType* merge_types(const BroType* t1, const BroType* t2) case TYPE_ADDR: case TYPE_NET: case TYPE_SUBNET: + case TYPE_BOOL: case TYPE_ANY: case TYPE_ERROR: return base_type(tg1); diff --git a/src/Type.h b/src/Type.h index ee991a13a3..05ca3adad1 100644 --- a/src/Type.h +++ b/src/Type.h @@ -525,6 +525,10 @@ public: int MatchesIndex(ListExpr*& index) const; + // Returns true if this table type is "unspecified", which is what one + // gets using an empty "vector()" constructor. + bool IsUnspecifiedVector() const; + protected: VectorType() { yield_type = 0; } diff --git a/testing/btest/Baseline/language.vector-coerce-expr/output b/testing/btest/Baseline/language.vector-coerce-expr/output new file mode 100644 index 0000000000..baabf9d89d --- /dev/null +++ b/testing/btest/Baseline/language.vector-coerce-expr/output @@ -0,0 +1,4 @@ +[] +[1, 2, 3] +[T, F, T] +[] diff --git a/testing/btest/language/vector-coerce-expr.bro b/testing/btest/language/vector-coerce-expr.bro new file mode 100644 index 0000000000..d58417f226 --- /dev/null +++ b/testing/btest/language/vector-coerce-expr.bro @@ -0,0 +1,20 @@ +# @TEST-EXEC: bro %INPUT >output 2>&1 +# @TEST-EXEC: btest-diff output + +type X: record { + a: vector of bool &default=vector(T, F, T); + b: vector of bool &default=vector(); +}; + +global x: X; + +global a: vector of count; + +a = vector(); +print a; + +a = vector(1,2,3); +print a; + +print x$a; +print x$b;