mirror of
https://github.com/zeek/zeek.git
synced 2025-10-04 15:48:19 +00:00
Add 'while' statement to Bro language.
This commit is contained in:
parent
212368b245
commit
062baefde0
9 changed files with 328 additions and 1 deletions
|
@ -181,6 +181,7 @@ SERIAL_STMT(INIT_STMT, 17)
|
|||
SERIAL_STMT(NULL_STMT, 18)
|
||||
SERIAL_STMT(WHEN_STMT, 19)
|
||||
SERIAL_STMT(FALLTHROUGH_STMT, 20)
|
||||
SERIAL_STMT(WHILE_STMT, 21)
|
||||
|
||||
#define SERIAL_TYPE(name, val) SERIAL_CONST(name, val, BRO_TYPE)
|
||||
SERIAL_TYPE(BRO_TYPE, 1)
|
||||
|
|
122
src/Stmt.cc
122
src/Stmt.cc
|
@ -23,7 +23,7 @@ const char* stmt_name(BroStmtTag t)
|
|||
"print", "event", "expr", "if", "when", "switch",
|
||||
"for", "next", "break", "return", "add", "delete",
|
||||
"list", "bodylist",
|
||||
"<init>", "fallthrough",
|
||||
"<init>", "fallthrough", "while",
|
||||
"null",
|
||||
};
|
||||
|
||||
|
@ -1127,6 +1127,126 @@ bool EventStmt::DoUnserialize(UnserialInfo* info)
|
|||
return event_expr != 0;
|
||||
}
|
||||
|
||||
WhileStmt::WhileStmt(Expr* arg_loop_condition, Stmt* arg_body)
|
||||
: loop_condition(arg_loop_condition), body(arg_body)
|
||||
{
|
||||
if ( ! loop_condition->IsError() &&
|
||||
! IsBool(loop_condition->Type()->Tag()) )
|
||||
loop_condition->Error("while conditional must be boolean");
|
||||
}
|
||||
|
||||
WhileStmt::~WhileStmt()
|
||||
{
|
||||
Unref(loop_condition);
|
||||
Unref(body);
|
||||
}
|
||||
|
||||
int WhileStmt::IsPure() const
|
||||
{
|
||||
return loop_condition->IsPure() && body->IsPure();
|
||||
}
|
||||
|
||||
void WhileStmt::Describe(ODesc* d) const
|
||||
{
|
||||
Stmt::Describe(d);
|
||||
|
||||
if ( d->IsReadable() )
|
||||
d->Add("(");
|
||||
|
||||
loop_condition->Describe(d);
|
||||
|
||||
if ( d->IsReadable() )
|
||||
d->Add(")");
|
||||
|
||||
d->SP();
|
||||
d->PushIndent();
|
||||
body->AccessStats(d);
|
||||
body->Describe(d);
|
||||
d->PopIndent();
|
||||
}
|
||||
|
||||
TraversalCode WhileStmt::Traverse(TraversalCallback* cb) const
|
||||
{
|
||||
TraversalCode tc = cb->PreStmt(this);
|
||||
HANDLE_TC_STMT_PRE(tc);
|
||||
|
||||
tc = loop_condition->Traverse(cb);
|
||||
HANDLE_TC_STMT_PRE(tc);
|
||||
|
||||
tc = body->Traverse(cb);
|
||||
HANDLE_TC_STMT_PRE(tc);
|
||||
|
||||
tc = cb->PostStmt(this);
|
||||
HANDLE_TC_STMT_POST(tc);
|
||||
}
|
||||
|
||||
Val* WhileStmt::Exec(Frame* f, stmt_flow_type& flow) const
|
||||
{
|
||||
RegisterAccess();
|
||||
flow = FLOW_NEXT;
|
||||
Val* rval = 0;
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
Val* cond = loop_condition->Eval(f);
|
||||
|
||||
if ( ! cond )
|
||||
break;
|
||||
|
||||
bool cont = cond->AsBool();
|
||||
Unref(cond);
|
||||
|
||||
if ( ! cont )
|
||||
break;
|
||||
|
||||
flow = FLOW_NEXT;
|
||||
rval = body->Exec(f, flow);
|
||||
|
||||
if ( flow == FLOW_BREAK || flow == FLOW_RETURN )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( flow == FLOW_LOOP || flow == FLOW_BREAK )
|
||||
flow = FLOW_NEXT;
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
Stmt* WhileStmt::Simplify()
|
||||
{
|
||||
loop_condition = simplify_expr(loop_condition, SIMPLIFY_GENERAL);
|
||||
|
||||
if ( loop_condition->IsConst() && loop_condition->IsZero() )
|
||||
return new NullStmt();
|
||||
|
||||
body = simplify_stmt(body);
|
||||
return this;
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIAL(WhileStmt, SER_WHILE_STMT);
|
||||
|
||||
bool WhileStmt::DoSerialize(SerialInfo* info) const
|
||||
{
|
||||
DO_SERIALIZE(SER_WHILE_STMT, Stmt);
|
||||
|
||||
if ( ! loop_condition->Serialize(info) )
|
||||
return false;
|
||||
|
||||
return body->Serialize(info);
|
||||
}
|
||||
|
||||
bool WhileStmt::DoUnserialize(UnserialInfo* info)
|
||||
{
|
||||
DO_UNSERIALIZE(Stmt);
|
||||
loop_condition = Expr::Unserialize(info);
|
||||
|
||||
if ( ! loop_condition )
|
||||
return false;
|
||||
|
||||
body = Stmt::Unserialize(info);
|
||||
return body != 0;
|
||||
}
|
||||
|
||||
ForStmt::ForStmt(id_list* arg_loop_vars, Expr* loop_expr)
|
||||
: ExprStmt(STMT_FOR, loop_expr)
|
||||
{
|
||||
|
|
29
src/Stmt.h
29
src/Stmt.h
|
@ -310,6 +310,35 @@ protected:
|
|||
EventExpr* event_expr;
|
||||
};
|
||||
|
||||
class WhileStmt : public Stmt {
|
||||
public:
|
||||
|
||||
WhileStmt(Expr* loop_condition, Stmt* body);
|
||||
|
||||
~WhileStmt();
|
||||
|
||||
int IsPure() const;
|
||||
|
||||
void Describe(ODesc* d) const;
|
||||
|
||||
TraversalCode Traverse(TraversalCallback* cb) const;
|
||||
|
||||
protected:
|
||||
friend class Stmt;
|
||||
|
||||
DECLARE_SERIAL(WhileStmt);
|
||||
|
||||
WhileStmt()
|
||||
{ loop_condition = 0; body = 0; }
|
||||
|
||||
Val* Exec(Frame* f, stmt_flow_type& flow) const;
|
||||
|
||||
Stmt* Simplify();
|
||||
|
||||
Expr* loop_condition;
|
||||
Stmt* body;
|
||||
};
|
||||
|
||||
class ForStmt : public ExprStmt {
|
||||
public:
|
||||
ForStmt(id_list* loop_vars, Expr* loop_expr);
|
||||
|
|
|
@ -17,6 +17,7 @@ typedef enum {
|
|||
STMT_LIST, STMT_EVENT_BODY_LIST,
|
||||
STMT_INIT,
|
||||
STMT_FALLTHROUGH,
|
||||
STMT_WHILE,
|
||||
STMT_NULL
|
||||
#define NUM_STMTS (int(STMT_NULL) + 1)
|
||||
} BroStmtTag;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
%token TOK_REMOVE_FROM TOK_RETURN TOK_SCHEDULE TOK_SET
|
||||
%token TOK_STRING TOK_SUBNET TOK_SWITCH TOK_TABLE
|
||||
%token TOK_TIME TOK_TIMEOUT TOK_TIMER TOK_TYPE TOK_UNION TOK_VECTOR TOK_WHEN
|
||||
%token TOK_WHILE
|
||||
|
||||
%token TOK_ATTR_ADD_FUNC TOK_ATTR_ENCRYPT TOK_ATTR_DEFAULT
|
||||
%token TOK_ATTR_OPTIONAL TOK_ATTR_REDEF TOK_ATTR_ROTATE_INTERVAL
|
||||
|
@ -1340,6 +1341,11 @@ stmt:
|
|||
$1->AsForStmt()->AddBody($2);
|
||||
}
|
||||
|
||||
| TOK_WHILE '(' expr ')' stmt
|
||||
{
|
||||
$$ = new WhileStmt($3, $5);
|
||||
}
|
||||
|
||||
| TOK_NEXT ';' opt_no_test
|
||||
{
|
||||
set_location(@1, @2);
|
||||
|
|
|
@ -221,6 +221,7 @@ export return TOK_EXPORT;
|
|||
fallthrough return TOK_FALLTHROUGH;
|
||||
file return TOK_FILE;
|
||||
for return TOK_FOR;
|
||||
while return TOK_WHILE;
|
||||
function return TOK_FUNCTION;
|
||||
global return TOK_GLOBAL;
|
||||
"?$" return TOK_HAS_FIELD;
|
||||
|
|
12
testing/btest/Baseline/language.while/out
Normal file
12
testing/btest/Baseline/language.while/out
Normal file
|
@ -0,0 +1,12 @@
|
|||
10
|
||||
s
|
||||
ss
|
||||
sss
|
||||
{
|
||||
7,
|
||||
1,
|
||||
9,
|
||||
5,
|
||||
3
|
||||
}
|
||||
[number 0, number 1, number 2, number 3, number 4, number 5, number 6, number 7, number 8, number 9, number 10, number 11, number 12]
|
80
testing/btest/core/leaks/while.bro
Normal file
80
testing/btest/core/leaks/while.bro
Normal file
|
@ -0,0 +1,80 @@
|
|||
# @TEST-GROUP: leaks
|
||||
# @TEST-REQUIRES: bro --help 2>&1 | grep -q mem-leaks
|
||||
|
||||
# @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -m -b -r $TRACES/http/get.trace %INPUT
|
||||
# @TEST-EXEC: btest-bg-wait 30
|
||||
|
||||
function test_noop()
|
||||
{
|
||||
while ( F )
|
||||
print "noooooooooo";
|
||||
}
|
||||
|
||||
function test_it()
|
||||
{
|
||||
local i = 0;
|
||||
|
||||
while ( i < 10 )
|
||||
++i;
|
||||
|
||||
print i;
|
||||
}
|
||||
|
||||
function test_break()
|
||||
{
|
||||
local s = "";
|
||||
|
||||
while ( T )
|
||||
{
|
||||
s += "s";
|
||||
print s;
|
||||
|
||||
if ( s == "sss" )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function test_next()
|
||||
{
|
||||
local s: set[count];
|
||||
local i = 0;
|
||||
|
||||
while ( 9 !in s )
|
||||
{
|
||||
++i;
|
||||
|
||||
if ( i % 2 == 0 )
|
||||
next;
|
||||
|
||||
add s[i];
|
||||
}
|
||||
|
||||
print s;
|
||||
}
|
||||
|
||||
function test_return(): vector of string
|
||||
{
|
||||
local i = 0;
|
||||
local rval: vector of string;
|
||||
|
||||
while ( T )
|
||||
{
|
||||
rval[i] = fmt("number %d", i);
|
||||
++i;
|
||||
|
||||
if ( i == 13 )
|
||||
return rval;
|
||||
}
|
||||
|
||||
rval[0] = "noooo";
|
||||
return rval;
|
||||
}
|
||||
|
||||
event new_connection(c: connection)
|
||||
{
|
||||
test_noop();
|
||||
test_it();
|
||||
test_break();
|
||||
test_next();
|
||||
print test_return();
|
||||
}
|
77
testing/btest/language/while.bro
Normal file
77
testing/btest/language/while.bro
Normal file
|
@ -0,0 +1,77 @@
|
|||
# @TEST-EXEC: bro -b %INPUT >out
|
||||
# @TEST-EXEC: btest-diff out
|
||||
|
||||
function test_noop()
|
||||
{
|
||||
while ( F )
|
||||
print "noooooooooo";
|
||||
}
|
||||
|
||||
function test_it()
|
||||
{
|
||||
local i = 0;
|
||||
|
||||
while ( i < 10 )
|
||||
++i;
|
||||
|
||||
print i;
|
||||
}
|
||||
|
||||
function test_break()
|
||||
{
|
||||
local s = "";
|
||||
|
||||
while ( T )
|
||||
{
|
||||
s += "s";
|
||||
print s;
|
||||
|
||||
if ( s == "sss" )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function test_next()
|
||||
{
|
||||
local s: set[count];
|
||||
local i = 0;
|
||||
|
||||
while ( 9 !in s )
|
||||
{
|
||||
++i;
|
||||
|
||||
if ( i % 2 == 0 )
|
||||
next;
|
||||
|
||||
add s[i];
|
||||
}
|
||||
|
||||
print s;
|
||||
}
|
||||
|
||||
function test_return(): vector of string
|
||||
{
|
||||
local i = 0;
|
||||
local rval: vector of string;
|
||||
|
||||
while ( T )
|
||||
{
|
||||
rval[i] = fmt("number %d", i);
|
||||
++i;
|
||||
|
||||
if ( i == 13 )
|
||||
return rval;
|
||||
}
|
||||
|
||||
rval[0] = "noooo";
|
||||
return rval;
|
||||
}
|
||||
|
||||
event bro_init()
|
||||
{
|
||||
test_noop();
|
||||
test_it();
|
||||
test_break();
|
||||
test_next();
|
||||
print test_return();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue