Merge remote-tracking branch 'origin/topic/jsiwek/remove-match'

* origin/topic/jsiwek/remove-match:
  Remove the match expression (addressed #753).
This commit is contained in:
Robin Sommer 2012-03-09 15:10:35 -08:00
parent 5b2b03c6f7
commit c78a391635
13 changed files with 14 additions and 259 deletions

View file

@ -1,4 +1,9 @@
2.0-145 | 2012-03-09 15:10:35 -0800
* Remove the match expression. 'match' and 'using' are no longer
keywords. Addressed #753. (Jon Siwek)
2.0-143 | 2012-03-09 15:07:42 -0800
* Fix a BRO_PROFILER_FILE/mkstemp portability issue. Addresses #794.

4
NEWS
View file

@ -24,6 +24,10 @@ Bro 2.1
- The connection compressor was already deprecated in 2.0 and has now
been removed from the code base.
- We removed the "match" statement, which was no longer used by any of
the default scripts, nor was it likely to be used by anybody anytime
soon. With that, "match" and "using" are no longer reserved keywords.
TODO: Extend.
Bro 2.0

View file

@ -1 +1 @@
2.0-143
2.0-145

View file

@ -3633,151 +3633,6 @@ bool FieldAssignExpr::DoUnserialize(UnserialInfo* info)
return true;
}
RecordMatchExpr::RecordMatchExpr(Expr* op1 /* record to match */,
Expr* op2 /* cases to match against */)
: BinaryExpr(EXPR_MATCH, op1, op2)
{
BroType* result_type = 0;
// Make sure the second argument is of a suitable type.
if ( ! op2->Type()->IsSet() )
{
ExprError("matching must be done against a set of match records");
return;
}
type_list* elt_types = op2->Type()->AsSetType()->Indices()->Types();
if ( ! elt_types->length() ||
(*elt_types)[0]->Tag() != TYPE_RECORD )
{
ExprError("matching must be done against a set of match records");
return;
}
RecordType* case_rec_type = (*elt_types)[0]->AsRecordType();
// NOTE: The "result" and "pred" field names are hardcoded here.
result_field_index = case_rec_type->FieldOffset("result");
if ( result_field_index < 0 )
{
ExprError("match records must have a $result field");
return;
}
result_type = case_rec_type->FieldType("result")->Ref();
// Check that pred exists, and that the first argument matches it.
if ( (pred_field_index = case_rec_type->FieldOffset("pred")) < 0 ||
case_rec_type->FieldType("pred")->Tag() != TYPE_FUNC )
{
ExprError("match records must have a $pred' field of function type");
return;
}
FuncType* pred_type = case_rec_type->FieldType("pred")->AsFuncType();
type_list* pred_arg_types = pred_type->ArgTypes()->Types();
if ( pred_arg_types->length() != 1 ||
! check_and_promote_expr(op1, (*pred_arg_types)[0]) )
ExprError("record to match does not have the same type as predicate argument");
// NOTE: The "priority" field name is hardcoded here.
if ( (priority_field_index = case_rec_type->FieldOffset("priority")) >= 0 &&
! IsArithmetic(case_rec_type->FieldType("priority")->Tag()) )
ExprError("$priority field must have a numeric type");
SetType(result_type);
}
void RecordMatchExpr::ExprDescribe(ODesc* d) const
{
if ( d->IsReadable() )
{
d->Add("match ");
op1->Describe(d);
d->Add(" using ");
op2->Describe(d);
}
}
Val* RecordMatchExpr::Fold(Val* v1, Val* v2) const
{
TableVal* match_set = v2->AsTableVal();
if ( ! match_set )
Internal("non-table in RecordMatchExpr");
Val* return_val = 0;
double highest_priority = -1e100;
ListVal* match_recs = match_set->ConvertToList(TYPE_ANY);
for ( int i = 0; i < match_recs->Length(); ++i )
{
val_list args(1);
args.append(v1->Ref());
double this_priority = 0;
// ### Get rid of the double Index if TYPE_ANY->TYPE_RECORD.
Val* v = match_recs->Index(i)->AsListVal()->Index(0);
const RecordVal* match_rec = v->AsRecordVal();
if ( ! match_rec )
Internal("Element of match set is not a record");
if ( priority_field_index >= 0 )
{
this_priority =
match_rec->Lookup(priority_field_index)->CoerceToDouble();
if ( this_priority <= highest_priority )
{
Unref(v1);
continue;
}
}
// No try/catch here; we pass exceptions upstream.
Val* pred_val =
match_rec->Lookup(pred_field_index)->AsFunc()->Call(&args);
bool is_zero = pred_val->IsZero();
Unref(pred_val);
if ( ! is_zero )
{
Val* new_return_val =
match_rec->Lookup(result_field_index);
Unref(return_val);
return_val = new_return_val->Ref();
if ( priority_field_index >= 0 )
highest_priority = this_priority;
else
break;
}
}
Unref(match_recs);
return return_val;
}
IMPLEMENT_SERIAL(RecordMatchExpr, SER_RECORD_MATCH_EXPR);
bool RecordMatchExpr::DoSerialize(SerialInfo* info) const
{
DO_SERIALIZE(SER_RECORD_MATCH_EXPR, BinaryExpr);
return SERIALIZE(pred_field_index) && SERIALIZE(result_field_index) &&
SERIALIZE(priority_field_index);
}
bool RecordMatchExpr::DoUnserialize(UnserialInfo* info)
{
DO_UNSERIALIZE(BinaryExpr);
return UNSERIALIZE(&pred_field_index) && UNSERIALIZE(&result_field_index) &&
UNSERIALIZE(&priority_field_index);
}
ArithCoerceExpr::ArithCoerceExpr(Expr* arg_op, TypeTag t)
: UnaryExpr(EXPR_ARITH_COERCE, arg_op)
{

View file

@ -823,32 +823,6 @@ protected:
string field_name;
};
class RecordMatchExpr : public BinaryExpr {
public:
RecordMatchExpr(Expr* op1 /* record to match */,
Expr* op2 /* cases to match against */);
protected:
friend class Expr;
RecordMatchExpr()
{
pred_field_index = result_field_index =
priority_field_index = 0;
}
virtual Val* Fold(Val* v1, Val* v2) const;
void ExprDescribe(ODesc*) const;
DECLARE_SERIAL(RecordMatchExpr);
// The following are used to hold the field offset of
// $pred, $result, $priority, so the names only need to
// be looked up at compile-time.
int pred_field_index;
int result_field_index;
int priority_field_index;
};
class ArithCoerceExpr : public UnaryExpr {
public:
ArithCoerceExpr(Expr* op, TypeTag t);

View file

@ -125,7 +125,7 @@ SERIAL_EXPR(FIELD_EXPR, 22)
SERIAL_EXPR(HAS_FIELD_EXPR, 23)
SERIAL_EXPR(RECORD_CONSTRUCTOR_EXPR, 24)
SERIAL_EXPR(FIELD_ASSIGN_EXPR, 25)
SERIAL_EXPR(RECORD_MATCH_EXPR, 26)
// There used to be a SERIAL_EXPR(RECORD_MATCH_EXPR, 26) here
SERIAL_EXPR(ARITH_COERCE_EXPR, 27)
SERIAL_EXPR(RECORD_COERCE_EXPR, 28)
SERIAL_EXPR(FLATTEN_EXPR, 29)

View file

@ -125,7 +125,7 @@ protected:
// This will be increased whenever there is an incompatible change
// in the data format.
static const uint32 DATA_FORMAT_VERSION = 21;
static const uint32 DATA_FORMAT_VERSION = 22;
ChunkedIO* io;

View file

@ -10,7 +10,7 @@
%token TOK_CONSTANT TOK_COPY TOK_COUNT TOK_COUNTER TOK_DEFAULT TOK_DELETE
%token TOK_DOUBLE TOK_ELSE TOK_ENUM TOK_EVENT TOK_EXPORT TOK_FILE TOK_FOR
%token TOK_FUNCTION TOK_GLOBAL TOK_ID TOK_IF TOK_INT
%token TOK_INTERVAL TOK_LIST TOK_LOCAL TOK_MODULE TOK_MATCH
%token TOK_INTERVAL TOK_LIST TOK_LOCAL TOK_MODULE
%token TOK_NEXT TOK_OF TOK_PATTERN TOK_PATTERN_TEXT
%token TOK_PORT TOK_PRINT TOK_RECORD TOK_REDEF
%token TOK_REMOVE_FROM TOK_RETURN TOK_SCHEDULE TOK_SET
@ -33,7 +33,7 @@
%left ',' '|'
%right '=' TOK_ADD_TO TOK_REMOVE_FROM
%right '?' ':' TOK_USING
%right '?' ':'
%left TOK_OR
%left TOK_AND
%nonassoc '<' '>' TOK_LE TOK_GE TOK_EQ TOK_NE
@ -504,12 +504,6 @@ expr:
$$ = new VectorConstructorExpr($3);
}
| TOK_MATCH expr TOK_USING expr
{
set_location(@1, @4);
$$ = new RecordMatchExpr($2, $4);
}
| expr '(' opt_expr_list ')'
{
set_location(@1, @4);

View file

@ -273,7 +273,6 @@ int return TOK_INT;
interval return TOK_INTERVAL;
list return TOK_LIST;
local return TOK_LOCAL;
match return TOK_MATCH;
module return TOK_MODULE;
next return TOK_NEXT;
of return TOK_OF;
@ -295,7 +294,6 @@ timeout return TOK_TIMEOUT;
timer return TOK_TIMER;
type return TOK_TYPE;
union return TOK_UNION;
using return TOK_USING;
vector return TOK_VECTOR;
when return TOK_WHEN;

View file

@ -1,3 +0,0 @@
default
it's big
it's really big

View file

@ -1,20 +0,0 @@
# @TEST-EXEC: bro %INPUT >output 2>&1
# @TEST-EXEC: btest-diff output
global match_stuff = {
[$pred(a: count) = { return a > 5; },
$result = "it's big",
$priority = 2],
[$pred(a: count) = { return a > 15; },
$result = "it's really big",
$priority = 3],
[$pred(a: count) = { return T; },
$result = "default",
$priority = 0],
};
print match 0 using match_stuff;
print match 10 using match_stuff;
print match 20 using match_stuff;

View file

@ -1,51 +0,0 @@
# @TEST-EXEC: bro %INPUT >output 2>&1
# @TEST-EXEC: btest-diff output
type fakealert : record {
alert: string;
};
type match_rec : record {
result : count;
pred : function(rec : fakealert) : bool;
priority: count;
};
#global test_set : set[int] =
#{
#1, 2, 3
#};
global match_set : set[match_rec] =
{
[$result = 1, $pred(a: fakealert) = { return T; }, $priority = 8 ],
[$result = 2, $pred(a: fakealert) = { return T; }, $priority = 9 ]
};
global al : fakealert;
#global testset : set[fakealert] =
#{
# [$alert="hithere"]
#};
type nonalert: record {
alert : string;
pred : function(a : int) : int;
};
#global na : nonalert;
#na$alert = "5";
#al$alert = "hithere2";
#if (al in testset)
# print 1;
#else
# print 0;
al$alert = "hi";
print (match al using match_set);