From bcf5c41786d981b04ed62629fb8db03677f3e700 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 30 May 2013 10:21:15 -0500 Subject: [PATCH] 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"];