Merge remote-tracking branch 'origin/topic/jsiwek/table-attribute-fixes'

* origin/topic/jsiwek/table-attribute-fixes:
  Fix various bugs with table/set attributes.

Closes #866.
This commit is contained in:
Robin Sommer 2012-12-03 14:11:14 -08:00
commit d9f90fcac0
8 changed files with 270 additions and 2 deletions

18
CHANGES
View file

@ -1,4 +1,22 @@
2.1-193 | 2012-12-03 14:11:14 -0800
* Fix a set of bugs with table/set attributes. (Jon Siwek)
- Identifiers that are initialized with set()/table() constructor
expressions now inherit attributes from the expression. Before,
statements like
const i: set[string] = set() &redef;
associated the attribute with the set() constructor, but not the
"i" identifier, preventing redefinition. Addresses #866.
- Allow &default attribute to apply to tables initialized as empty
(via either "{ }" or "table()") or if the expression supplied to it
can evaluate to a type that's promotable to the same yield type as
the table.
2.1-191 | 2012-12-03 14:08:56 -0800
* Add test of record() constructor to table initializer unit test.

View file

@ -1 +1 @@
2.1-191
2.1-193

View file

@ -260,6 +260,11 @@ void Attributes::CheckAttr(Attr* a)
// Ok.
break;
if ( type->Tag() == TYPE_TABLE &&
type->AsTableType()->IsUnspecifiedTable() )
// Ok.
break;
a->AttrExpr()->Error("&default value has inconsistent type", type);
}
@ -290,6 +295,11 @@ void Attributes::CheckAttr(Attr* a)
// Ok.
break;
Expr* e = a->AttrExpr();
if ( check_and_promote_expr(e, ytype) )
// Ok.
break;
Error("&default value has inconsistent type 2");
}

View file

@ -3445,7 +3445,7 @@ Val* SetConstructorExpr::Eval(Frame* f) const
if ( IsError() )
return 0;
TableVal* aggr = new TableVal(type->AsTableType(), 0);
TableVal* aggr = new TableVal(type->AsTableType(), attrs);
const expr_list& exprs = op->AsListExpr()->Exprs();
loop_over_list(exprs, i)

View file

@ -747,6 +747,8 @@ public:
TableConstructorExpr(ListExpr* constructor_list, attr_list* attrs);
~TableConstructorExpr() { Unref(attrs); }
Attributes* Attrs() { return attrs; }
Val* Eval(Frame* f) const;
protected:
@ -767,6 +769,8 @@ public:
SetConstructorExpr(ListExpr* constructor_list, attr_list* attrs);
~SetConstructorExpr() { Unref(attrs); }
Attributes* Attrs() { return attrs; }
Val* Eval(Frame* f) const;
protected:

View file

@ -109,6 +109,36 @@ static void make_var(ID* id, BroType* t, init_class c, Expr* init,
if ( attr )
id->AddAttrs(new Attributes(attr, t, false));
if ( init )
{
switch ( init->Tag() ) {
case EXPR_TABLE_CONSTRUCTOR:
{
TableConstructorExpr* ctor = (TableConstructorExpr*) init;
if ( ctor->Attrs() )
{
::Ref(ctor->Attrs());
id->AddAttrs(ctor->Attrs());
}
}
break;
case EXPR_SET_CONSTRUCTOR:
{
SetConstructorExpr* ctor = (SetConstructorExpr*) init;
if ( ctor->Attrs() )
{
::Ref(ctor->Attrs());
id->AddAttrs(ctor->Attrs());
}
}
break;
default:
break;
}
}
if ( id->FindAttr(ATTR_PERSISTENT) || id->FindAttr(ATTR_SYNCHRONIZED) )
{
if ( dt == VAR_CONST )

View file

@ -0,0 +1,91 @@
my_set_ctor_init
{
test2,
test3,
test4,
test1
}
my_table_ctor_init
{
[2] = test2,
[1] = test1,
[3] = test3
}
nope
my_set_init
{
test2,
test3,
test4,
test1
}
my_table_init
{
[2] = test2,
[4] = test4,
[1] = test1,
[3] = test3
}
nope
inception
{
[0] = {
[13] = bar
}
}
{
[13] = bar
}
bar
forty-two
{
}
we need to go deeper
{
[0] = {
[13] = bar
}
}
{
[13] = bar
}
bar
forty-two
{
}
we need to go deeper
local table t1
{
[1] = foo
}
foo
nope
local table t2
{
[1] = foo
}
foo
nope
local table t3
{
}
nope
nope
local table t4
{
}
nope
nope

View file

@ -0,0 +1,115 @@
# @TEST-EXEC: bro -b %INPUT >output
# @TEST-EXEC: btest-diff output
# set()/table() constructors are allowed to have attributes. When initializing
# an identifier, those attributes should also apply to it.
const my_set_ctor_init: set[string] = set("test1") &redef;
redef my_set_ctor_init += {
"test2",
"test3",
};
redef my_set_ctor_init += set("test4");
const my_table_ctor_init: table[count] of string = table([1] = "test1") &redef &default="nope";
redef my_table_ctor_init += {
[2] = "test2",
[3] = "test3",
};
# initializer list versions work the same way.
const my_set_init: set[string] = { "test1" } &redef;
redef my_set_init += {
"test2",
"test3",
};
redef my_set_init += set("test4");
const my_table_init: table[count] of string = { [1] = "test1" } &redef &default="nope";
redef my_table_init += {
[2] = "test2",
[3] = "test3",
};
redef my_table_init += table([4] = "test4");
# For tables that yield tables, we can apply attributes to the both other and
# inner tables...
global inception_table: table[count] of table[count] of string = table(
[0] = table([13] = "bar") &default="forty-two"
) &default=table() &default="we need to go deeper";
global inception_table2: table[count] of table[count] of string = {
[0] = table([13] = "bar") &default="forty-two",
} &default=table() &default="we need to go deeper";
event bro_init()
{
print "my_set_ctor_init";
print my_set_ctor_init;
print "";
print "my_table_ctor_init";
print my_table_ctor_init;
print my_table_ctor_init[5];
print "";
print "my_set_init";
print my_set_init;
print "";
print "my_table_init";
print my_table_init;
print my_table_init[5];
print "";
print "inception";
print inception_table;
print inception_table[0];
print inception_table[0][13];
print inception_table[0][42];
print inception_table[1];
print inception_table[1][2];
print inception_table2;
print inception_table2[0];
print inception_table2[0][13];
print inception_table2[0][42];
print inception_table2[1];
print inception_table2[1][2];
print "";
# just checking attributes on locals works, too
print "local table t1";
local t1: table[count] of string = table([1] = "foo") &default="nope";
print t1;
print t1[1];
print t1[2];
print "";
print "local table t2";
local t2: table[count] of string = {[1] = "foo"} &default="nope";
print t2;
print t2[1];
print t2[2];
print "";
# and for empty initializers...
print "local table t3";
local t3: table[count] of string = table() &default="nope";
print t3;
print t3[1];
print t3[2];
print "";
print "local table t4";
local t4: table[count] of string = {} &default="nope";
print t4;
print t4[1];
print t4[2];
print "";
}