From a0ad87b4c2ac9c1028d7c22f231d57c5d6fa5184 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Wed, 29 May 2013 12:48:15 -0500 Subject: [PATCH 1/6] Allow named record constructors. Addresses #983. --- src/Expr.cc | 41 +++++++++++++++++-- src/Expr.h | 17 +++++++- src/Type.h | 5 +++ src/parse.y | 35 ++++++++++++++-- .../btest/Baseline/language.named-ctors/out | 2 + testing/btest/language/named-ctors.bro | 12 ++++++ 6 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 testing/btest/Baseline/language.named-ctors/out create mode 100644 testing/btest/language/named-ctors.bro diff --git a/src/Expr.cc b/src/Expr.cc index 12d3d72304..32fc9b5acc 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -3320,12 +3320,20 @@ bool HasFieldExpr::DoUnserialize(UnserialInfo* info) return UNSERIALIZE(¬_used) && UNSERIALIZE_STR(&field_name, 0) && UNSERIALIZE(&field); } -RecordConstructorExpr::RecordConstructorExpr(ListExpr* constructor_list) +RecordConstructorExpr::RecordConstructorExpr(ListExpr* constructor_list, + BroType* arg_type) : UnaryExpr(EXPR_RECORD_CONSTRUCTOR, constructor_list) { if ( IsError() ) return; + if ( arg_type && arg_type->Tag() != TYPE_RECORD ) + { + Error("bad record constructor type", arg_type); + SetError(); + return; + } + // Spin through the list, which should be comprised of // either record's or record-field-assign, and build up a // record type to associate with this constructor. @@ -3365,7 +3373,17 @@ RecordConstructorExpr::RecordConstructorExpr(ListExpr* constructor_list) } } - SetType(new RecordType(record_types)); + ctor_type = new RecordType(record_types); + + if ( arg_type ) + SetType(arg_type->Ref()); + else + SetType(ctor_type->Ref()); + } + +RecordConstructorExpr::~RecordConstructorExpr() + { + Unref(ctor_type); } Val* RecordConstructorExpr::InitVal(const BroType* t, Val* aggr) const @@ -3391,7 +3409,7 @@ Val* RecordConstructorExpr::InitVal(const BroType* t, Val* aggr) const Val* RecordConstructorExpr::Fold(Val* v) const { ListVal* lv = v->AsListVal(); - RecordType* rt = type->AsRecordType(); + RecordType* rt = ctor_type->AsRecordType(); if ( lv->Length() != rt->NumFields() ) Internal("inconsistency evaluating record constructor"); @@ -3401,6 +3419,19 @@ Val* RecordConstructorExpr::Fold(Val* v) const for ( int i = 0; i < lv->Length(); ++i ) rv->Assign(i, lv->Index(i)->Ref()); + if ( ! same_type(rt, type) ) + { + RecordVal* new_val = rv->CoerceTo(type->AsRecordType()); + + if ( new_val ) + { + Unref(rv); + rv = new_val; + } + else + Internal("record constructor coercion failed"); + } + return rv; } @@ -3416,12 +3447,16 @@ IMPLEMENT_SERIAL(RecordConstructorExpr, SER_RECORD_CONSTRUCTOR_EXPR); bool RecordConstructorExpr::DoSerialize(SerialInfo* info) const { DO_SERIALIZE(SER_RECORD_CONSTRUCTOR_EXPR, UnaryExpr); + SERIALIZE_OPTIONAL(ctor_type); return true; } bool RecordConstructorExpr::DoUnserialize(UnserialInfo* info) { DO_UNSERIALIZE(UnaryExpr); + BroType* t = 0; + UNSERIALIZE_OPTIONAL(t, RecordType::Unserialize(info)); + ctor_type = t->AsRecordType(); return true; } diff --git a/src/Expr.h b/src/Expr.h index bb7526d502..edc1ced6e5 100644 --- a/src/Expr.h +++ b/src/Expr.h @@ -57,6 +57,7 @@ extern const char* expr_name(BroExprTag t); class Stmt; class Frame; class ListExpr; +class NameExpr; class CallExpr; class EventExpr; @@ -165,6 +166,17 @@ public: return (ListExpr*) this; } + const NameExpr* AsNameExpr() const + { + CHECK_TAG(tag, EXPR_NAME, "ExprVal::AsNameExpr", expr_name) + return (const NameExpr*) this; + } + NameExpr* AsNameExpr() + { + CHECK_TAG(tag, EXPR_NAME, "ExprVal::AsNameExpr", expr_name) + return (NameExpr*) this; + } + void Describe(ODesc* d) const; bool Serialize(SerialInfo* info) const; @@ -729,7 +741,8 @@ protected: class RecordConstructorExpr : public UnaryExpr { public: - RecordConstructorExpr(ListExpr* constructor_list); + RecordConstructorExpr(ListExpr* constructor_list, BroType* arg_type = 0); + ~RecordConstructorExpr(); protected: friend class Expr; @@ -741,6 +754,8 @@ protected: void ExprDescribe(ODesc* d) const; DECLARE_SERIAL(RecordConstructorExpr); + + RecordType* ctor_type; // type inferred from the ctor expression list args }; class TableConstructorExpr : public UnaryExpr { diff --git a/src/Type.h b/src/Type.h index 0b7620cd68..bad51776d9 100644 --- a/src/Type.h +++ b/src/Type.h @@ -217,6 +217,11 @@ public: return tag == TYPE_TABLE && (YieldType() == 0); } + int IsTable() const + { + return tag == TYPE_TABLE && (YieldType() != 0); + } + BroType* Ref() { ::Ref(this); return this; } virtual void Describe(ODesc* d) const; diff --git a/src/parse.y b/src/parse.y index 7ce1174595..bfaf282c6a 100644 --- a/src/parse.y +++ b/src/parse.y @@ -522,10 +522,39 @@ expr: $$ = new VectorConstructorExpr($3); } - | expr '(' opt_expr_list ')' + | expr '(' { - set_location(@1, @4); - $$ = new CallExpr($1, $3, in_hook > 0); + if ( $1->Tag() == EXPR_NAME && $1->Type()->IsTable() ) + ++in_init; + } + opt_expr_list + { + if ( $1->Tag() == EXPR_NAME && $1->Type()->IsTable() ) + --in_init; + } + ')' + { + set_location(@1, @6); + + BroType* ctor_type = 0; + + if ( $1->Tag() == EXPR_NAME && + (ctor_type = $1->AsNameExpr()->Id()->AsType()) ) + { + switch ( ctor_type->Tag() ) { + case TYPE_RECORD: + $$ = new RecordConstructorExpr($4, ctor_type); + break; + case TYPE_TABLE: + case TYPE_VECTOR: + default: + $1->Error("constructor type not implemented"); + YYERROR; + } + } + + else + $$ = new CallExpr($1, $4, in_hook > 0); } | TOK_HOOK { ++in_hook; } expr diff --git a/testing/btest/Baseline/language.named-ctors/out b/testing/btest/Baseline/language.named-ctors/out new file mode 100644 index 0000000000..39b2ed7c0b --- /dev/null +++ b/testing/btest/Baseline/language.named-ctors/out @@ -0,0 +1,2 @@ +[min=, max=2] +[min=7, max=42] diff --git a/testing/btest/language/named-ctors.bro b/testing/btest/language/named-ctors.bro new file mode 100644 index 0000000000..7f04b9d4b0 --- /dev/null +++ b/testing/btest/language/named-ctors.bro @@ -0,0 +1,12 @@ +# @TEST-EXEC: bro -b %INPUT >out +# @TEST-EXEC: btest-diff out + +type MyRec: record { + min: count &optional; + max: count; +}; + +local myrec: MyRec = MyRec($max=2); +print myrec; +myrec = MyRec($min=7, $max=42); +print myrec; From b256642f273e4b53cd9520acebd3bf5b4fdde60d Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Wed, 29 May 2013 15:11:44 -0500 Subject: [PATCH 2/6] Allow named set constructors. Addresses #983. --- src/Expr.cc | 59 +++++++++++++++++-- src/Expr.h | 3 +- src/parse.y | 9 +++ .../out | 0 .../Baseline/language.named-set-ctors/out | 9 +++ ...named-ctors.bro => named-record-ctors.bro} | 0 testing/btest/language/named-set-ctors.bro | 11 ++++ 7 files changed, 86 insertions(+), 5 deletions(-) rename testing/btest/Baseline/{language.named-ctors => language.named-record-ctors}/out (100%) create mode 100644 testing/btest/Baseline/language.named-set-ctors/out rename testing/btest/language/{named-ctors.bro => named-record-ctors.bro} (100%) create mode 100644 testing/btest/language/named-set-ctors.bro diff --git a/src/Expr.cc b/src/Expr.cc index 32fc9b5acc..0888ee6336 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -3537,16 +3537,30 @@ bool TableConstructorExpr::DoUnserialize(UnserialInfo* info) } SetConstructorExpr::SetConstructorExpr(ListExpr* constructor_list, - attr_list* arg_attrs) + attr_list* arg_attrs, BroType* arg_type) : UnaryExpr(EXPR_SET_CONSTRUCTOR, constructor_list) { if ( IsError() ) return; - if ( constructor_list->Exprs().length() == 0 ) - SetType(new ::SetType(new TypeList(base_type(TYPE_ANY)), 0)); + if ( arg_type ) + { + if ( ! arg_type->IsSet() ) + { + Error("bad set constructor type", arg_type); + SetError(); + return; + } + + SetType(arg_type->Ref()); + } else - SetType(init_type(constructor_list)); + { + 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(); @@ -3555,6 +3569,43 @@ SetConstructorExpr::SetConstructorExpr(ListExpr* constructor_list, 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(); + + loop_over_list(cle, i) + { + Expr* ce = cle[i]; + + if ( ce->Tag() == EXPR_LIST ) + { + // check promote each expression in composite index + expr_list& el = ce->AsListExpr()->Exprs(); + + if ( el.length() != indices->length() ) + { + ExprError("inconsistent index type length in set constructor"); + return; + } + + loop_over_list(el, j) + { + Expr* e = el[j]; + + if ( ! check_and_promote_expr(e, (*indices)[j]) ) + { + ExprError("inconsistent index type in set constructor"); + return; + } + } + } + + else if ( indices->length() == 1 ) + { + if ( ! check_and_promote_expr(ce, (*indices)[0]) ) + ExprError("inconsistent index type in set constructor"); + } + } } Val* SetConstructorExpr::Eval(Frame* f) const diff --git a/src/Expr.h b/src/Expr.h index edc1ced6e5..e2cc1375a3 100644 --- a/src/Expr.h +++ b/src/Expr.h @@ -782,7 +782,8 @@ protected: class SetConstructorExpr : public UnaryExpr { public: - SetConstructorExpr(ListExpr* constructor_list, attr_list* attrs); + SetConstructorExpr(ListExpr* constructor_list, attr_list* attrs, + BroType* arg_type = 0); ~SetConstructorExpr() { Unref(attrs); } Attributes* Attrs() { return attrs; } diff --git a/src/parse.y b/src/parse.y index bfaf282c6a..ac57dea5e9 100644 --- a/src/parse.y +++ b/src/parse.y @@ -546,6 +546,15 @@ expr: $$ = new RecordConstructorExpr($4, ctor_type); break; case TYPE_TABLE: + if ( ctor_type->IsTable() ) + { + $1->Error("constructor type not implemented"); + YYERROR; + } + else + $$ = new SetConstructorExpr($4, 0, ctor_type); + + break; case TYPE_VECTOR: default: $1->Error("constructor type not implemented"); diff --git a/testing/btest/Baseline/language.named-ctors/out b/testing/btest/Baseline/language.named-record-ctors/out similarity index 100% rename from testing/btest/Baseline/language.named-ctors/out rename to testing/btest/Baseline/language.named-record-ctors/out diff --git a/testing/btest/Baseline/language.named-set-ctors/out b/testing/btest/Baseline/language.named-set-ctors/out new file mode 100644 index 0000000000..e7b0ca6b67 --- /dev/null +++ b/testing/btest/Baseline/language.named-set-ctors/out @@ -0,0 +1,9 @@ +{ +1, +5, +3 +} +{ +[test, 1] , +[cool, 2] +} diff --git a/testing/btest/language/named-ctors.bro b/testing/btest/language/named-record-ctors.bro similarity index 100% rename from testing/btest/language/named-ctors.bro rename to testing/btest/language/named-record-ctors.bro diff --git a/testing/btest/language/named-set-ctors.bro b/testing/btest/language/named-set-ctors.bro new file mode 100644 index 0000000000..5c7e0b1398 --- /dev/null +++ b/testing/btest/language/named-set-ctors.bro @@ -0,0 +1,11 @@ +# @TEST-EXEC: bro -b %INPUT >out +# @TEST-EXEC: btest-diff out + +type FooSet: set[count]; +type FooSetComp: set[string, count]; + +global myset: FooSet = FooSet(1, 5, 3); +global mysetcomp: FooSetComp = FooSetComp(["test", 1], ["cool", 2]); + +print myset; +print mysetcomp; From 29740d3d6e5eb311f22f3ddd7b5407371ecab7eb Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Wed, 29 May 2013 16:49:12 -0500 Subject: [PATCH 3/6] Improve set constructor argument coercion. --- src/Expr.cc | 41 ++++++++----------- .../Baseline/language.named-set-ctors/out | 4 ++ testing/btest/language/named-set-ctors.bro | 8 ++++ 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/src/Expr.cc b/src/Expr.cc index 0888ee6336..777fa5fe26 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -3573,37 +3573,30 @@ SetConstructorExpr::SetConstructorExpr(ListExpr* constructor_list, type_list* indices = type->AsTableType()->Indices()->Types(); expr_list& cle = constructor_list->Exprs(); - loop_over_list(cle, i) + if ( indices->length() == 1 ) { - Expr* ce = cle[i]; + if ( ! check_and_promote_exprs_to_type(constructor_list, + (*indices)[0]) ) + ExprError("inconsistent type in set constructor"); + } - if ( ce->Tag() == EXPR_LIST ) + else if ( indices->length() > 1 ) + { + // check/promote each expression in composite index + loop_over_list(cle, i) { - // check promote each expression in composite index - expr_list& el = ce->AsListExpr()->Exprs(); + Expr* ce = cle[i]; + ListExpr* le = ce->AsListExpr(); - if ( el.length() != indices->length() ) + if ( ce->Tag() == EXPR_LIST && + check_and_promote_exprs(le, type->AsTableType()->Indices()) ) { - ExprError("inconsistent index type length in set constructor"); - return; + if ( le != cle[i] ) + cle.replace(i, le); + continue; } - loop_over_list(el, j) - { - Expr* e = el[j]; - - if ( ! check_and_promote_expr(e, (*indices)[j]) ) - { - ExprError("inconsistent index type in set constructor"); - return; - } - } - } - - else if ( indices->length() == 1 ) - { - if ( ! check_and_promote_expr(ce, (*indices)[0]) ) - ExprError("inconsistent index type in set constructor"); + ExprError("inconsistent types in set constructor"); } } } diff --git a/testing/btest/Baseline/language.named-set-ctors/out b/testing/btest/Baseline/language.named-set-ctors/out index e7b0ca6b67..66b0baed7f 100644 --- a/testing/btest/Baseline/language.named-set-ctors/out +++ b/testing/btest/Baseline/language.named-set-ctors/out @@ -4,6 +4,10 @@ 3 } { +[min=, max=5], +[min=, max=2] +} +{ [test, 1] , [cool, 2] } diff --git a/testing/btest/language/named-set-ctors.bro b/testing/btest/language/named-set-ctors.bro index 5c7e0b1398..083937c42e 100644 --- a/testing/btest/language/named-set-ctors.bro +++ b/testing/btest/language/named-set-ctors.bro @@ -1,11 +1,19 @@ # @TEST-EXEC: bro -b %INPUT >out # @TEST-EXEC: btest-diff out +type MyRec: record { + min: count &optional; + max: count; +}; + type FooSet: set[count]; +type FooSetRec: set[MyRec]; type FooSetComp: set[string, count]; global myset: FooSet = FooSet(1, 5, 3); +global mysetrec: FooSetRec = FooSetRec([$max=5], [$max=2]); global mysetcomp: FooSetComp = FooSetComp(["test", 1], ["cool", 2]); print myset; +print mysetrec; print mysetcomp; From bcf5c41786d981b04ed62629fb8db03677f3e700 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 30 May 2013 10:21:15 -0500 Subject: [PATCH 4/6] Allow named table constructors. Addresses #983. --- src/Expr.cc | 66 ++++++++++++++++--- src/Expr.h | 15 ++++- src/parse.y | 7 +- .../Baseline/language.named-table-ctors/out | 19 ++++++ testing/btest/language/named-table-ctors.bro | 24 +++++++ 5 files changed, 117 insertions(+), 14 deletions(-) create mode 100644 testing/btest/Baseline/language.named-table-ctors/out create mode 100644 testing/btest/language/named-table-ctors.bro diff --git a/src/Expr.cc b/src/Expr.cc index 777fa5fe26..ca980e5acc 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -3461,27 +3461,75 @@ bool RecordConstructorExpr::DoUnserialize(UnserialInfo* info) } TableConstructorExpr::TableConstructorExpr(ListExpr* constructor_list, - attr_list* arg_attrs) + attr_list* arg_attrs, BroType* arg_type) : UnaryExpr(EXPR_TABLE_CONSTRUCTOR, constructor_list) { if ( IsError() ) return; - if ( constructor_list->Exprs().length() == 0 ) - SetType(new TableType(new TypeList(base_type(TYPE_ANY)), 0)); + if ( arg_type ) + { + if ( ! arg_type->IsTable() ) + { + Error("bad table constructor type", arg_type); + SetError(); + return; + } + + SetType(arg_type->Ref()); + } else { - SetType(init_type(constructor_list)); + 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(); + if ( ! type ) + SetError(); - else if ( type->Tag() != TYPE_TABLE || - type->AsTableType()->IsSet() ) - SetError("values in table(...) constructor do not specify a table"); + 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(); + 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 diff --git a/src/Expr.h b/src/Expr.h index e2cc1375a3..ff97c52178 100644 --- a/src/Expr.h +++ b/src/Expr.h @@ -58,6 +58,7 @@ class Stmt; class Frame; class ListExpr; class NameExpr; +class AssignExpr; class CallExpr; class EventExpr; @@ -177,6 +178,17 @@ public: return (NameExpr*) this; } + const AssignExpr* AsAssignExpr() const + { + CHECK_TAG(tag, EXPR_ASSIGN, "ExprVal::AsAssignExpr", expr_name) + return (const AssignExpr*) this; + } + AssignExpr* AsAssignExpr() + { + CHECK_TAG(tag, EXPR_ASSIGN, "ExprVal::AsAssignExpr", expr_name) + return (AssignExpr*) this; + } + void Describe(ODesc* d) const; bool Serialize(SerialInfo* info) const; @@ -760,7 +772,8 @@ protected: class TableConstructorExpr : public UnaryExpr { public: - TableConstructorExpr(ListExpr* constructor_list, attr_list* attrs); + TableConstructorExpr(ListExpr* constructor_list, attr_list* attrs, + BroType* arg_type = 0); ~TableConstructorExpr() { Unref(attrs); } Attributes* Attrs() { return attrs; } diff --git a/src/parse.y b/src/parse.y index ac57dea5e9..74588408fa 100644 --- a/src/parse.y +++ b/src/parse.y @@ -545,16 +545,15 @@ expr: case TYPE_RECORD: $$ = new RecordConstructorExpr($4, ctor_type); break; + case TYPE_TABLE: if ( ctor_type->IsTable() ) - { - $1->Error("constructor type not implemented"); - YYERROR; - } + $$ = new TableConstructorExpr($4, 0, ctor_type); else $$ = new SetConstructorExpr($4, 0, ctor_type); break; + case TYPE_VECTOR: default: $1->Error("constructor type not implemented"); diff --git a/testing/btest/Baseline/language.named-table-ctors/out b/testing/btest/Baseline/language.named-table-ctors/out new file mode 100644 index 0000000000..23554d10f6 --- /dev/null +++ b/testing/btest/Baseline/language.named-table-ctors/out @@ -0,0 +1,19 @@ +{ +[1] = one, +[5] = five, +[3] = three +} +{ +[[min=, max=5]] = max5, +[[min=, max=2]] = max2 +} +{ +[test, 1] = test1, +[cool, 2] = cool2 +} +{ +[two] = 2.0, +[one] = 1.0, +[three] = 3.0 +} +0 diff --git a/testing/btest/language/named-table-ctors.bro b/testing/btest/language/named-table-ctors.bro new file mode 100644 index 0000000000..83500488f1 --- /dev/null +++ b/testing/btest/language/named-table-ctors.bro @@ -0,0 +1,24 @@ +# @TEST-EXEC: bro -b %INPUT >out +# @TEST-EXEC: btest-diff out + +type MyRec: record { + min: count &optional; + max: count; +}; + +type FooTable: table[count] of string; +type FooTableRec: table[MyRec] of string; +type FooTableComp: table[string, count] of string; +type FooTableY: table[string] of double; + +global mytable: FooTable = FooTable([1] = "one", [5] = "five", [3] = "three"); +global mytablerec: FooTableRec = FooTableRec([[$max=5]] = "max5", [[$max=2]] = "max2"); +global mytablecomp: FooTableComp = FooTableComp(["test", 1] = "test1", ["cool", +2] = "cool2"); +global mytabley: FooTableY = FooTableY(["one"] = 1, ["two"] = 2, ["three"] = 3) &default=0; + +print mytable; +print mytablerec; +print mytablecomp; +print mytabley; +print mytabley["test"]; From a66b7380b6690003c1b0f321f4f7459a8469a901 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 30 May 2013 10:57:28 -0500 Subject: [PATCH 5/6] Allow named vector constructors. Addresses #983. --- src/Expr.cc | 51 +++++++++++++------ src/Expr.h | 2 +- src/parse.y | 3 ++ .../Baseline/language.named-vector-ctors/out | 3 ++ testing/btest/language/named-vector-ctors.bro | 19 +++++++ 5 files changed, 61 insertions(+), 17 deletions(-) create mode 100644 testing/btest/Baseline/language.named-vector-ctors/out create mode 100644 testing/btest/language/named-vector-ctors.bro diff --git a/src/Expr.cc b/src/Expr.cc index ca980e5acc..556c153643 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -3717,31 +3717,50 @@ bool SetConstructorExpr::DoUnserialize(UnserialInfo* info) return true; } -VectorConstructorExpr::VectorConstructorExpr(ListExpr* constructor_list) +VectorConstructorExpr::VectorConstructorExpr(ListExpr* constructor_list, + BroType* arg_type) : UnaryExpr(EXPR_VECTOR_CONSTRUCTOR, constructor_list) { if ( IsError() ) return; - if ( constructor_list->Exprs().length() == 0 ) + if ( arg_type ) { - // vector(). - SetType(new ::VectorType(base_type(TYPE_ANY))); - return; - } + if ( arg_type->Tag() != TYPE_VECTOR ) + { + Error("bad vector constructor type", arg_type); + SetError(); + return; + } - BroType* t = merge_type_list(constructor_list); - if ( t ) - { - SetType(new VectorType(t->Ref())); - - if ( ! check_and_promote_exprs_to_type(constructor_list, t) ) - ExprError("inconsistent types in vector constructor"); - - Unref(t); + SetType(arg_type->Ref()); } else - SetError(); + { + if ( constructor_list->Exprs().length() == 0 ) + { + // vector(). + SetType(new ::VectorType(base_type(TYPE_ANY))); + 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 diff --git a/src/Expr.h b/src/Expr.h index ff97c52178..2dca42ef09 100644 --- a/src/Expr.h +++ b/src/Expr.h @@ -818,7 +818,7 @@ protected: class VectorConstructorExpr : public UnaryExpr { public: - VectorConstructorExpr(ListExpr* constructor_list); + VectorConstructorExpr(ListExpr* constructor_list, BroType* arg_type = 0); Val* Eval(Frame* f) const; diff --git a/src/parse.y b/src/parse.y index 74588408fa..2b86057f3c 100644 --- a/src/parse.y +++ b/src/parse.y @@ -555,6 +555,9 @@ expr: break; case TYPE_VECTOR: + $$ = new VectorConstructorExpr($4, ctor_type); + break; + default: $1->Error("constructor type not implemented"); YYERROR; diff --git a/testing/btest/Baseline/language.named-vector-ctors/out b/testing/btest/Baseline/language.named-vector-ctors/out new file mode 100644 index 0000000000..53ed260c93 --- /dev/null +++ b/testing/btest/Baseline/language.named-vector-ctors/out @@ -0,0 +1,3 @@ +[one, two, three] +[1.0, 2.0, 3.0] +[[min=, max=1], [min=, max=2], [min=, max=3]] diff --git a/testing/btest/language/named-vector-ctors.bro b/testing/btest/language/named-vector-ctors.bro new file mode 100644 index 0000000000..1e0e1e9e55 --- /dev/null +++ b/testing/btest/language/named-vector-ctors.bro @@ -0,0 +1,19 @@ +# @TEST-EXEC: bro -b %INPUT >out +# @TEST-EXEC: btest-diff out + +type MyRec: record { + min: count &optional; + max: count; +}; + +type FooVector: vector of string; +type FooVectorD: vector of double; +type FooVectorRec: vector of MyRec; + +global myvec: FooVector = FooVector("one", "two", "three"); +global myvecd: FooVectorD = FooVectorD(1, 2, 3); +global myvecrec: FooVectorRec = FooVectorRec([$max=1], [$max=2], [$max=3]); + +print myvec; +print myvecd; +print myvecrec; From 4301002f1adcf31ce23c61239671a6f5e19f47e7 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 30 May 2013 11:41:22 -0500 Subject: [PATCH 6/6] Add named constructor examples to docs. --- doc/scripts/builtins.rst | 75 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/doc/scripts/builtins.rst b/doc/scripts/builtins.rst index 369f38c9eb..937c0ea00d 100644 --- a/doc/scripts/builtins.rst +++ b/doc/scripts/builtins.rst @@ -246,6 +246,31 @@ The Bro scripting language supports the following built-in types. [5] = "five", }; + A table constructor (equivalent to above example) can also be used + to create a table: + + .. code:: bro + + global t2: table[count] of string = table( + [11] = "eleven", + [5] = "five" + ); + + Table constructors can also be explicitly named by a type, which is + useful for when a more complex index type could otherwise be + ambiguous: + + .. code:: bro + + type MyRec: record { + a: count &optional; + b: count; + }; + + type MyTable: table[MyRec] of string; + + global t3 = MyTable([[$b=5]] = "b5", [[$b=7]] = "b7"); + Accessing table elements if provided by enclosing values within square brackets (``[]``), for example: @@ -308,6 +333,28 @@ The Bro scripting language supports the following built-in types. The types are explicitly shown in the example above, but they could have been left to type inference. + A set constructor (equivalent to above example) can also be used to + create a set: + + .. code:: bro + + global s3: set[port] = set(21/tcp, 23/tcp, 80/tcp 443/tcp); + + Set constructors can also be explicitly named by a type, which is + useful for when a more complex index type could otherwise be + ambiguous: + + .. code:: bro + + type MyRec: record { + a: count &optional; + b: count; + }; + + type MySet: set[MyRec]; + + global s4 = MySet([$b=1], [$b=2]); + Set membership is tested with ``in``: .. code:: bro @@ -349,6 +396,21 @@ The Bro scripting language supports the following built-in types. global v: vector of string = vector("one", "two", "three"); + Vector constructors can also be explicitly named by a type, which + is useful for when a more complex yield type could otherwise be + ambiguous. + + .. code:: bro + + type MyRec: record { + a: count &optional; + b: count; + }; + + type MyVec: vector of MyRec; + + global v2 = MyVec([$b=1], [$b=2], [$b=3]); + Adding an element to a vector involves accessing/assigning it: .. code:: bro @@ -402,6 +464,19 @@ The Bro scripting language supports the following built-in types. if ( r?$s ) ... + Records can also be created using a constructor syntax: + + .. code:: bro + + global r2: MyRecordType = record($c = 7); + + And the constructor can be explicitly named by type, too, which + is arguably more readable code: + + .. code:: bro + + global r3 = MyRecordType($c = 42); + .. bro:type:: opaque A data type whose actual representation/implementation is