Branch data Line data Source code
1 : : // $Id: Stmt.cc 6916 2009-09-24 20:48:36Z vern $
2 : : //
3 : : // See the file "COPYING" in the main distribution directory for copyright.
4 : :
5 : : #include "config.h"
6 : :
7 : : #include "Expr.h"
8 : : #include "Event.h"
9 : : #include "Frame.h"
10 : : #include "File.h"
11 : : #include "Logger.h"
12 : : #include "NetVar.h"
13 : : #include "Stmt.h"
14 : : #include "Scope.h"
15 : : #include "Var.h"
16 : : #include "Debug.h"
17 : : #include "Traverse.h"
18 : : #include "Trigger.h"
19 : : #include "RemoteSerializer.h"
20 : :
21 : 0 : const char* stmt_name(BroStmtTag t)
22 : : {
23 : : static const char* stmt_names[int(NUM_STMTS)] = {
24 : : "alarm", "print", "event", "expr", "if", "when", "switch",
25 : : "for", "next", "break", "return", "add", "delete",
26 : : "list", "bodylist",
27 : : "<init>",
28 : : "null",
29 : : };
30 : :
31 : 0 : return stmt_names[int(t)];
32 : : }
33 : :
34 : 10505 : Stmt::Stmt(BroStmtTag arg_tag)
35 : : {
36 : 10505 : tag = arg_tag;
37 : 10505 : breakpoint_count = 0;
38 : 10505 : last_access = 0;
39 : 10505 : access_count = 0;
40 : :
41 : 10505 : SetLocationInfo(&start_location, &end_location);
42 : 10505 : }
43 : :
44 : 109 : Stmt::~Stmt()
45 : : {
46 [ # # ][ # # ]: 109 : }
[ - + ]
47 : :
48 : 18987 : bool Stmt::SetLocationInfo(const Location* start, const Location* end)
49 : : {
50 [ - + ]: 18987 : if ( ! BroObj::SetLocationInfo(start, end) )
51 : 0 : return false;
52 : :
53 : : // Update the Filemap of line number -> statement mapping for
54 : : // breakpoints (Debug.h).
55 : 18987 : Filemap* map_ptr = (Filemap*) g_dbgfilemaps.Lookup(location->filename);
56 [ + - ]: 18987 : if ( ! map_ptr )
57 : 18987 : return false;
58 : :
59 : 0 : Filemap& map = *map_ptr;
60 : :
61 : 0 : StmtLocMapping* new_mapping = new StmtLocMapping(GetLocationInfo(), this);
62 : :
63 : : // Optimistically just put it at the end.
64 : 0 : map.push_back(new_mapping);
65 : :
66 : 0 : int curr_idx = map.length() - 1;
67 [ # # ]: 0 : if ( curr_idx == 0 )
68 : 0 : return true;
69 : :
70 : : // In case it wasn't actually lexically last, bubble it to the
71 : : // right place.
72 [ # # ]: 0 : while ( map[curr_idx - 1]->StartsAfter(map[curr_idx]) )
73 : : {
74 : 0 : StmtLocMapping t = *map[curr_idx - 1];
75 : 0 : *map[curr_idx - 1] = *map[curr_idx];
76 : 0 : *map[curr_idx] = t;
77 : 0 : curr_idx--;
78 : : }
79 : :
80 : 18987 : return true;
81 : : }
82 : :
83 : 0 : Stmt* Stmt::Simplify()
84 : : {
85 : 0 : return this;
86 : : }
87 : :
88 : 0 : int Stmt::IsPure() const
89 : : {
90 : 0 : return 0;
91 : : }
92 : :
93 : 0 : void Stmt::Describe(ODesc* d) const
94 : : {
95 [ # # ][ # # ]: 0 : if ( ! d->IsReadable() || Tag() != STMT_EXPR )
[ # # ]
96 : 0 : AddTag(d);
97 : 0 : }
98 : :
99 : 0 : void Stmt::AddTag(ODesc* d) const
100 : : {
101 [ # # ]: 0 : if ( d->IsBinary() )
102 : 0 : d->Add(int(Tag()));
103 : : else
104 : 0 : d->Add(stmt_name(Tag()));
105 : 0 : d->SP();
106 : 0 : }
107 : :
108 : 0 : void Stmt::DescribeDone(ODesc* d) const
109 : : {
110 [ # # ][ # # ]: 0 : if ( d->IsReadable() && ! d->IsShort() )
[ # # ]
111 : 0 : d->Add(";");
112 : 0 : }
113 : :
114 : 0 : void Stmt::AccessStats(ODesc* d) const
115 : : {
116 [ # # ]: 0 : if ( d->IncludeStats() )
117 : : {
118 : 0 : d->Add("(@");
119 [ # # ]: 0 : d->Add(last_access ? fmt_access_time(last_access) : "<never>");
120 : 0 : d->Add(" #");
121 : 0 : d->Add(access_count);
122 : 0 : d->Add(")");
123 : 0 : d->NL();
124 : : }
125 : 0 : }
126 : :
127 : 0 : bool Stmt::Serialize(SerialInfo* info) const
128 : : {
129 : 0 : return SerialObj::Serialize(info);
130 : : }
131 : :
132 : 0 : Stmt* Stmt::Unserialize(UnserialInfo* info, BroStmtTag want)
133 : : {
134 : 0 : Stmt* stmt = (Stmt*) SerialObj::Unserialize(info, SER_STMT);
135 : :
136 [ # # # # ]: 0 : if ( want != STMT_ANY && stmt->tag != want )
137 : : {
138 : 0 : info->s->Error("wrong stmt type");
139 : 0 : Unref(stmt);
140 : 0 : return 0;
141 : : }
142 : :
143 : 0 : return stmt;
144 : : }
145 : :
146 : 0 : bool Stmt::DoSerialize(SerialInfo* info) const
147 : : {
148 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_STMT, BroObj);
149 : :
150 : : return SERIALIZE(char(tag)) && SERIALIZE(last_access)
151 [ # # ][ # # ]: 0 : && SERIALIZE(access_count);
[ # # ]
152 : : }
153 : :
154 : 0 : bool Stmt::DoUnserialize(UnserialInfo* info)
155 : : {
156 [ # # ]: 0 : DO_UNSERIALIZE(BroObj);
157 : :
158 : : char c;
159 [ # # ]: 0 : if ( ! UNSERIALIZE(&c) )
160 : 0 : return 0;
161 : :
162 : 0 : tag = BroStmtTag(c);
163 : :
164 [ # # ][ # # ]: 0 : return UNSERIALIZE(&last_access) && UNSERIALIZE(&access_count);
165 : : }
166 : :
167 : :
168 : 281 : ExprListStmt::ExprListStmt(BroStmtTag t, ListExpr* arg_l)
169 : 281 : : Stmt(t)
170 : : {
171 : 281 : l = arg_l;
172 : :
173 : 281 : const expr_list& e = l->Exprs();
174 [ # # ][ + + ]: 792 : loop_over_list(e, i)
175 : : {
176 : 511 : const BroType* t = e[i]->Type();
177 [ # # # # ]: 511 : if ( ! t || t->Tag() == TYPE_VOID )
[ # # + - ]
[ - + ][ - + ]
178 : 0 : Error("value of type void illegal");
179 : : }
180 : :
181 : 281 : SetLocationInfo(arg_l->GetLocationInfo());
182 : 281 : }
183 : :
184 : 0 : ExprListStmt::~ExprListStmt()
185 : : {
186 : 0 : Unref(l);
187 [ # # ][ # # ]: 0 : }
[ # # ]
188 : :
189 : 6344 : Val* ExprListStmt::Exec(Frame* f, stmt_flow_type& flow) const
190 : : {
191 : 6344 : last_access = network_time;
192 : 6344 : flow = FLOW_NEXT;
193 : :
194 : 6344 : val_list* vals = eval_list(f, l);
195 [ + - ]: 6344 : if ( vals )
196 : : {
197 : 6344 : Val* result = DoExec(vals, flow);
198 : 6344 : delete_vals(vals);
199 : 6344 : return result;
200 : : }
201 : : else
202 : 6344 : return 0;
203 : : }
204 : :
205 : 0 : Stmt* ExprListStmt::Simplify()
206 : : {
207 : 0 : l = simplify_expr_list(l, SIMPLIFY_GENERAL);
208 : 0 : DoSimplify();
209 : 0 : return this;
210 : : }
211 : :
212 : 0 : Stmt* ExprListStmt::DoSimplify()
213 : : {
214 : 0 : return this;
215 : : }
216 : :
217 : 0 : void ExprListStmt::Describe(ODesc* d) const
218 : : {
219 : 0 : Stmt::Describe(d);
220 : 0 : l->Describe(d);
221 : 0 : DescribeDone(d);
222 : 0 : }
223 : :
224 : 6344 : void ExprListStmt::PrintVals(ODesc* d, val_list* vals, int offset) const
225 : : {
226 : 6344 : describe_vals(vals, d, offset);
227 : 6344 : }
228 : :
229 : 0 : bool ExprListStmt::DoSerialize(SerialInfo* info) const
230 : : {
231 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_EXPR_LIST_STMT, Stmt);
232 : 0 : return l->Serialize(info);
233 : : }
234 : :
235 : 0 : bool ExprListStmt::DoUnserialize(UnserialInfo* info)
236 : : {
237 [ # # ]: 0 : DO_UNSERIALIZE(Stmt);
238 : 0 : l = (ListExpr*) Expr::Unserialize(info, EXPR_LIST);
239 : 0 : return l != 0;
240 : : }
241 : :
242 : 0 : TraversalCode ExprListStmt::Traverse(TraversalCallback* cb) const
243 : : {
244 : 0 : TraversalCode tc = cb->PreStmt(this);
245 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
246 : :
247 : 0 : const expr_list& e = l->Exprs();
248 [ # # ]: 0 : loop_over_list(e, i)
249 : : {
250 : 0 : tc = e[i]->Traverse(cb);
251 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
252 : : }
253 : :
254 : 0 : tc = cb->PostStmt(this);
255 [ # # ][ # # ]: 0 : HANDLE_TC_STMT_POST(tc);
256 : : }
257 : :
258 : 1379 : Val* AlarmStmt::DoExec(val_list* vals, stmt_flow_type& /* flow */) const
259 : : {
260 : 1379 : ODesc d;
261 : 1379 : PrintVals(&d, vals, 0);
262 : :
263 [ - + ]: 1379 : if ( alarm_hook )
264 : : {
265 : 0 : ListExpr* args = new ListExpr();
266 : 0 : args->Append(new ConstExpr(new StringVal(d.Description())));
267 : :
268 : : CallExpr* ce =
269 : 0 : new CallExpr(new ConstExpr(new Val(alarm_hook)), args);
270 : :
271 : 0 : Val* hook_eval = ce->Eval(0);
272 : 0 : int do_log = hook_eval->IsOne();
273 : :
274 : 0 : Unref(ce);
275 : 0 : Unref(hook_eval);
276 : :
277 [ # # ]: 0 : if ( ! do_log )
278 : 0 : return 0;
279 : : }
280 : :
281 : 1379 : bro_logger->Log(d.Description());
282 : 1379 : return 0;
283 : : }
284 : :
285 : 3 : IMPLEMENT_SERIAL(AlarmStmt, SER_ALARM_STMT);
286 : :
287 : 0 : bool AlarmStmt::DoSerialize(SerialInfo* info) const
288 : : {
289 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_ALARM_STMT, ExprListStmt);
290 : 0 : return true;
291 : : }
292 : :
293 : 0 : bool AlarmStmt::DoUnserialize(UnserialInfo* info)
294 : : {
295 [ # # ]: 0 : DO_UNSERIALIZE(ExprListStmt);
296 : 0 : return true;
297 : : }
298 : :
299 : : static BroFile* print_stdout = 0;
300 : :
301 : 4965 : Val* PrintStmt::DoExec(val_list* vals, stmt_flow_type& /* flow */) const
302 : : {
303 [ + + ]: 4965 : if ( ! print_stdout )
304 : 1 : print_stdout = new BroFile(stdout);
305 : :
306 : 4965 : BroFile* f = print_stdout;
307 : 4965 : int offset = 0;
308 : :
309 [ + - ][ + - ]: 4965 : if ( vals->length() > 0 && (*vals)[0]->Type()->Tag() == TYPE_FILE )
[ + - ]
310 : : {
311 : 4965 : f = (*vals)[0]->AsFile();
312 [ - + ]: 4965 : if ( ! f->IsOpen() )
313 : 0 : return 0;
314 : :
315 : 4965 : ++offset;
316 : : }
317 : :
318 [ - + ][ # # ]: 4965 : bool ph = print_hook && f->IsPrintHookEnabled();
319 : :
320 [ - + ]: 4965 : desc_style style = f->IsRawOutput() ? ALTERNATIVE_STYLE : STANDARD_STYLE;
321 : :
322 [ - + ][ # # ]: 4965 : if ( ! (suppress_local_output && ph) )
323 : : {
324 : 4965 : ODesc d(DESC_READABLE, f);
325 : 4965 : d.SetFlush(0);
326 : 4965 : d.SetStyle(style);
327 : :
328 : 4965 : PrintVals(&d, vals, offset);
329 : 4965 : f->Write("\n", 1);
330 : : }
331 : :
332 [ - + ]: 4965 : if ( ph )
333 : : {
334 : 0 : ODesc d(DESC_READABLE);
335 : 0 : d.SetStyle(style);
336 : 0 : PrintVals(&d, vals, offset);
337 : :
338 [ # # ]: 0 : if ( print_hook )
339 : : {
340 : 0 : val_list* vl = new val_list(2);
341 : 0 : ::Ref(f);
342 : 0 : vl->append(new Val(f));
343 : 0 : vl->append(new StringVal(d.Description()));
344 : :
345 : : // Note, this doesn't do remote printing.
346 : 0 : mgr.Dispatch(new Event(print_hook, vl), true);
347 : : }
348 : :
349 [ # # ]: 0 : if ( remote_serializer )
350 : 0 : remote_serializer->SendPrintHookEvent(f, d.Description());
351 : : }
352 : :
353 : 4965 : return 0;
354 : : }
355 : :
356 : 3 : IMPLEMENT_SERIAL(PrintStmt, SER_PRINT_STMT);
357 : :
358 : 0 : bool PrintStmt::DoSerialize(SerialInfo* info) const
359 : : {
360 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_PRINT_STMT, ExprListStmt);
361 : 0 : return true;
362 : : }
363 : :
364 : 0 : bool PrintStmt::DoUnserialize(UnserialInfo* info)
365 : : {
366 [ # # ]: 0 : DO_UNSERIALIZE(ExprListStmt);
367 : 0 : return true;
368 : : }
369 : :
370 : 3564 : ExprStmt::ExprStmt(Expr* arg_e) : Stmt(STMT_EXPR)
371 : : {
372 : 3564 : e = arg_e;
373 [ + - - + ]: 3564 : if ( e && e->IsPure() )
[ - + # # ]
[ # # ][ # # ]
374 : 0 : Warn("expression value ignored");
375 : :
376 : 3564 : SetLocationInfo(arg_e->GetLocationInfo());
377 : 3564 : }
378 : :
379 : 3017 : ExprStmt::ExprStmt(BroStmtTag t, Expr* arg_e) : Stmt(t)
380 : : {
381 : 3017 : e = arg_e;
382 : :
383 [ # # + + ]: 3017 : if ( e )
384 : 2814 : SetLocationInfo(e->GetLocationInfo());
385 : 3017 : }
386 : :
387 : 1 : ExprStmt::~ExprStmt()
388 : : {
389 : 1 : Unref(e);
390 [ # # ][ # # ]: 1 : }
[ - + ]
391 : :
392 : 454774 : Val* ExprStmt::Exec(Frame* f, stmt_flow_type& flow) const
393 : : {
394 : 454774 : RegisterAccess();
395 : 454774 : flow = FLOW_NEXT;
396 : :
397 : 454774 : Val* v = e->Eval(f);
398 : :
399 [ + + ]: 454774 : if ( v )
400 : : {
401 : 443748 : Val* ret_val = DoExec(f, v, flow);
402 : 443748 : Unref(v);
403 : 443748 : return ret_val;
404 : : }
405 : : else
406 : 454774 : return 0;
407 : : }
408 : :
409 : 244223 : Val* ExprStmt::DoExec(Frame* /* f */, Val* /* v */, stmt_flow_type& /* flow */) const
410 : : {
411 : 244223 : return 0;
412 : : }
413 : :
414 : 0 : Stmt* ExprStmt::Simplify()
415 : : {
416 : 0 : e = simplify_expr(e, SIMPLIFY_GENERAL);
417 : 0 : return DoSimplify();
418 : : }
419 : :
420 : 0 : Stmt* ExprStmt::DoSimplify()
421 : : {
422 : 0 : return this;
423 : : }
424 : :
425 : 0 : int ExprStmt::IsPure() const
426 : : {
427 [ # # ][ # # ]: 0 : return ! e || e->IsPure();
428 : : }
429 : :
430 : 0 : void ExprStmt::Describe(ODesc* d) const
431 : : {
432 : 0 : Stmt::Describe(d);
433 : :
434 [ # # # # ]: 0 : if ( d->IsReadable() && Tag() == STMT_IF )
[ # # ]
435 : 0 : d->Add("(");
436 : 0 : e->Describe(d);
437 : :
438 [ # # # # ]: 0 : if ( Tag() == STMT_IF || Tag() == STMT_SWITCH )
[ # # ]
439 : : {
440 [ # # ]: 0 : if ( d->IsReadable() )
441 : : {
442 [ # # ]: 0 : if ( Tag() == STMT_IF )
443 : 0 : d->Add(")");
444 : 0 : d->SP();
445 : : }
446 : : }
447 : : else
448 : 0 : DescribeDone(d);
449 : 0 : }
450 : :
451 : 0 : TraversalCode ExprStmt::Traverse(TraversalCallback* cb) const
452 : : {
453 : 0 : TraversalCode tc = cb->PreStmt(this);
454 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
455 : :
456 [ # # ]: 0 : if ( e )
457 : : {
458 : 0 : tc = e->Traverse(cb);
459 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
460 : : }
461 : :
462 : 0 : tc = cb->PostStmt(this);
463 [ # # ][ # # ]: 0 : HANDLE_TC_STMT_POST(tc);
464 : : }
465 : :
466 : 3 : IMPLEMENT_SERIAL(ExprStmt, SER_EXPR_STMT);
467 : :
468 : 0 : bool ExprStmt::DoSerialize(SerialInfo* info) const
469 : : {
470 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_EXPR_STMT, Stmt);
471 [ # # ][ # # ]: 0 : SERIALIZE_OPTIONAL(e);
[ # # ][ # # ]
[ # # ][ # # ]
472 : 0 : return true;
473 : : }
474 : :
475 : 0 : bool ExprStmt::DoUnserialize(UnserialInfo* info)
476 : : {
477 [ # # ]: 0 : DO_UNSERIALIZE(Stmt);
478 [ # # ][ # # ]: 0 : UNSERIALIZE_OPTIONAL(e, Expr::Unserialize(info));
[ # # ]
479 : 0 : return true;
480 : : }
481 : :
482 : 1725 : IfStmt::IfStmt(Expr* test, Stmt* arg_s1, Stmt* arg_s2) : ExprStmt(STMT_IF, test)
483 : : {
484 : 1725 : s1 = arg_s1;
485 : 1725 : s2 = arg_s2;
486 : :
487 [ + - - + ]: 1725 : if ( ! e->IsError() && ! IsBool(e->Type()->Tag()) )
[ - + # # ]
[ # # ][ # # ]
488 : 0 : e->Error("conditional in test must be boolean");
489 : :
490 : 1725 : const Location* loc1 = arg_s1->GetLocationInfo();
491 : 1725 : const Location* loc2 = arg_s2->GetLocationInfo();
492 : 1725 : SetLocationInfo(loc1, loc2);
493 : 1725 : }
494 : :
495 : 0 : IfStmt::~IfStmt()
496 : : {
497 : 0 : Unref(s1);
498 : 0 : Unref(s2);
499 [ # # ][ # # ]: 0 : }
[ # # ]
500 : :
501 : 175768 : Val* IfStmt::DoExec(Frame* f, Val* v, stmt_flow_type& flow) const
502 : : {
503 : : // Treat 0 as false, but don't require 1 for true.
504 [ + + ]: 175768 : Stmt* do_stmt = v->IsZero() ? s2 : s1;
505 : :
506 : 175768 : f->SetNextStmt(do_stmt);
507 : :
508 : 175768 : if ( ! pre_execute_stmt(do_stmt, f) )
509 : : { // ### Abort or something
510 : : }
511 : :
512 : 175768 : Val* result = do_stmt->Exec(f, flow);
513 : :
514 : 175768 : if ( ! post_execute_stmt(do_stmt, f, result, &flow) )
515 : : { // ### Abort or something
516 : : }
517 : :
518 : 175768 : return result;
519 : : }
520 : :
521 : 0 : Stmt* IfStmt::DoSimplify()
522 : : {
523 : 0 : s1 = simplify_stmt(s1);
524 : 0 : s2 = simplify_stmt(s2);
525 : :
526 [ # # ]: 0 : if ( e->IsConst() )
527 : : {
528 [ # # ]: 0 : if ( ! optimize )
529 : 0 : Warn("constant in conditional");
530 : :
531 [ # # ]: 0 : return e->IsZero() ? s2->Ref() : s1->Ref();
532 : : }
533 : :
534 [ # # ]: 0 : if ( e->Tag() == EXPR_NOT )
535 : : {
536 : 0 : Stmt* t = s1;
537 : 0 : s1 = s2;
538 : 0 : s2 = t;
539 : :
540 : 0 : e = new NotExpr(e);
541 : :
542 : 0 : return Simplify();
543 : : }
544 : :
545 : 0 : return this;
546 : : }
547 : :
548 : 0 : int IfStmt::IsPure() const
549 : : {
550 [ # # ][ # # ]: 0 : return e->IsPure() && s1->IsPure() && s2->IsPure();
[ # # ]
551 : : }
552 : :
553 : 0 : void IfStmt::Describe(ODesc* d) const
554 : : {
555 : 0 : ExprStmt::Describe(d);
556 : :
557 : 0 : d->PushIndent();
558 : 0 : s1->AccessStats(d);
559 : 0 : s1->Describe(d);
560 : 0 : d->PopIndent();
561 : :
562 [ # # ]: 0 : if ( d->IsReadable() )
563 : : {
564 [ # # ]: 0 : if ( s2->Tag() != STMT_NULL )
565 : : {
566 : 0 : d->Add("else");
567 : 0 : d->PushIndent();
568 : 0 : s2->AccessStats(d);
569 : 0 : s2->Describe(d);
570 : 0 : d->PopIndent();
571 : : }
572 : : }
573 : : else
574 : 0 : s2->Describe(d);
575 : 0 : }
576 : :
577 : 0 : TraversalCode IfStmt::Traverse(TraversalCallback* cb) const
578 : : {
579 : 0 : TraversalCode tc = cb->PreStmt(this);
580 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
581 : :
582 : : // Condition is stored in base class's "e" field.
583 : 0 : tc = e->Traverse(cb);
584 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
585 : :
586 : 0 : tc = TrueBranch()->Traverse(cb);
587 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
588 : :
589 : 0 : tc = FalseBranch()->Traverse(cb);
590 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
591 : :
592 : 0 : tc = cb->PostStmt(this);
593 [ # # ][ # # ]: 0 : HANDLE_TC_STMT_POST(tc);
594 : : }
595 : :
596 : 3 : IMPLEMENT_SERIAL(IfStmt, SER_IF_STMT);
597 : :
598 : 0 : bool IfStmt::DoSerialize(SerialInfo* info) const
599 : : {
600 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_IF_STMT, ExprStmt);
601 [ # # ][ # # ]: 0 : return s1->Serialize(info) && s2->Serialize(info);
602 : : }
603 : :
604 : 0 : bool IfStmt::DoUnserialize(UnserialInfo* info)
605 : : {
606 [ # # ]: 0 : DO_UNSERIALIZE(ExprStmt);
607 : 0 : s1 = Stmt::Unserialize(info);
608 [ # # ]: 0 : if ( ! s1 )
609 : 0 : return false;
610 : :
611 : 0 : s2 = Stmt::Unserialize(info);
612 : 0 : return s2 != 0;
613 : : }
614 : :
615 : 0 : Case::~Case()
616 : : {
617 : 0 : Unref(cases);
618 : 0 : Unref(s);
619 [ # # ][ # # ]: 0 : }
[ # # ]
620 : :
621 : 0 : void Case::Describe(ODesc* d) const
622 : : {
623 : 0 : const expr_list& e = Cases()->Exprs();
624 : :
625 [ # # ]: 0 : if ( ! d->IsBinary() )
626 : 0 : d->Add("case");
627 : :
628 : 0 : d->AddCount(e.length());
629 : :
630 [ # # ]: 0 : loop_over_list(e, j)
631 : : {
632 [ # # ][ # # ]: 0 : if ( j > 0 && ! d->IsReadable() )
[ # # ]
633 : 0 : d->Add(",");
634 : :
635 : 0 : d->SP();
636 : 0 : e[j]->Describe(d);
637 : : }
638 : :
639 [ # # ]: 0 : if ( d->IsReadable() )
640 : 0 : d->Add(":");
641 : :
642 : 0 : d->PushIndent();
643 : 0 : Body()->AccessStats(d);
644 : 0 : Body()->Describe(d);
645 : 0 : d->PopIndent();
646 : 0 : }
647 : :
648 : 0 : TraversalCode Case::Traverse(TraversalCallback* cb) const
649 : : {
650 : 0 : TraversalCode tc = cases->Traverse(cb);
651 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
652 : :
653 : 0 : tc = s->Traverse(cb);
654 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
655 : :
656 : 0 : return TC_CONTINUE;
657 : : }
658 : :
659 : 0 : bool Case::Serialize(SerialInfo* info) const
660 : : {
661 : 0 : return SerialObj::Serialize(info);
662 : : }
663 : :
664 : 0 : Case* Case::Unserialize(UnserialInfo* info)
665 : : {
666 : 0 : return (Case*) SerialObj::Unserialize(info, SER_CASE);
667 : : }
668 : :
669 : 3 : IMPLEMENT_SERIAL(Case, SER_CASE);
670 : :
671 : 0 : bool Case::DoSerialize(SerialInfo* info) const
672 : : {
673 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_CASE, BroObj);
674 [ # # ][ # # ]: 0 : return cases->Serialize(info) && this->s->Serialize(info);
675 : : }
676 : :
677 : 0 : bool Case::DoUnserialize(UnserialInfo* info)
678 : : {
679 [ # # ]: 0 : DO_UNSERIALIZE(BroObj);
680 : :
681 : 0 : cases = (ListExpr*) Expr::Unserialize(info, EXPR_LIST);
682 [ # # ]: 0 : if ( ! cases )
683 : 0 : return false;
684 : :
685 : 0 : this->s = Stmt::Unserialize(info);
686 : 0 : return this->s != 0;
687 : : }
688 : :
689 : 0 : SwitchStmt::SwitchStmt(Expr* index, case_list* arg_cases) :
690 : 0 : ExprStmt(STMT_SWITCH, index)
691 : : {
692 : 0 : cases = arg_cases;
693 : :
694 : : //### need to loop over cases and make sure their type matches
695 : : //### the index, and they're constant and not redundant
696 : 0 : }
697 : :
698 : 0 : SwitchStmt::~SwitchStmt()
699 : : {
700 [ # # ][ # # ]: 0 : loop_over_list(*cases, i)
[ # # ]
701 : 0 : Unref((*cases)[i]);
702 : :
703 [ # # ][ # # ]: 0 : delete cases;
[ # # ]
704 [ # # ][ # # ]: 0 : }
[ # # ]
705 : :
706 : 0 : Val* SwitchStmt::DoExec(Frame* /* f */, Val* /* v */, stmt_flow_type& /* flow */) const
707 : : {
708 : 0 : printf("switch statement not implemented\n");
709 : 0 : return 0;
710 : : }
711 : :
712 : 0 : Stmt* SwitchStmt::DoSimplify()
713 : : {
714 [ # # ]: 0 : loop_over_list(*cases, i)
715 : : {
716 : 0 : Case* c = (*cases)[i];
717 : 0 : ListExpr* new_cases = simplify_expr_list(c->Cases(), SIMPLIFY_GENERAL);
718 : 0 : Stmt* new_body = simplify_stmt(c->Body());
719 : :
720 [ # # # # ]: 0 : if ( new_cases != c->Cases() || new_body != c->Body() )
[ # # ]
721 : : {
722 : 0 : cases->replace(i, new Case(new_cases, new_body));
723 : 0 : Unref(c);
724 : : }
725 : : }
726 : :
727 [ # # ]: 0 : if ( e->IsConst() )
728 : : { // ### go through cases and pull out the one it matches
729 [ # # ]: 0 : if ( ! optimize )
730 : 0 : Warn("constant in switch");
731 : : }
732 : :
733 : 0 : return this;
734 : : }
735 : :
736 : 0 : int SwitchStmt::IsPure() const
737 : : {
738 [ # # ]: 0 : if ( ! e->IsPure() )
739 : 0 : return 0;
740 : :
741 [ # # ]: 0 : loop_over_list(*cases, i)
742 : : {
743 : 0 : Case* c = (*cases)[i];
744 [ # # # # ]: 0 : if ( ! c->Cases()->IsPure() || ! c->Body()->IsPure() )
[ # # ]
745 : 0 : return 0;
746 : : }
747 : :
748 : 0 : return 1;
749 : : }
750 : :
751 : 0 : void SwitchStmt::Describe(ODesc* d) const
752 : : {
753 : 0 : ExprStmt::Describe(d);
754 : :
755 [ # # ]: 0 : if ( ! d->IsBinary() )
756 : 0 : d->Add("{");
757 : :
758 : 0 : d->PushIndent();
759 : 0 : d->AddCount(cases->length());
760 [ # # ]: 0 : loop_over_list(*cases, i)
761 : 0 : (*cases)[i]->Describe(d);
762 : 0 : d->PopIndent();
763 : :
764 [ # # ]: 0 : if ( ! d->IsBinary() )
765 : 0 : d->Add("}");
766 : 0 : d->NL();
767 : 0 : }
768 : :
769 : 0 : TraversalCode SwitchStmt::Traverse(TraversalCallback* cb) const
770 : : {
771 : 0 : TraversalCode tc = cb->PreStmt(this);
772 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
773 : :
774 : : // Index is stored in base class's "e" field.
775 : 0 : tc = e->Traverse(cb);
776 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
777 : :
778 [ # # ]: 0 : loop_over_list(*cases, i)
779 : : {
780 : 0 : tc = (*cases)[i]->Traverse(cb);
781 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
782 : : }
783 : :
784 : 0 : tc = cb->PostStmt(this);
785 [ # # ][ # # ]: 0 : HANDLE_TC_STMT_POST(tc);
786 : : }
787 : :
788 : 3 : IMPLEMENT_SERIAL(SwitchStmt, SER_SWITCH_STMT);
789 : :
790 : 0 : bool SwitchStmt::DoSerialize(SerialInfo* info) const
791 : : {
792 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_SWITCH_STMT, ExprStmt);
793 : :
794 [ # # ]: 0 : if ( ! SERIALIZE(cases->length()) )
795 : 0 : return false;
796 : :
797 [ # # ]: 0 : loop_over_list((*cases), i)
798 [ # # ]: 0 : if ( ! (*cases)[i]->Serialize(info) )
799 : 0 : return false;
800 : :
801 : 0 : return true;
802 : : }
803 : :
804 : 0 : bool SwitchStmt::DoUnserialize(UnserialInfo* info)
805 : : {
806 [ # # ]: 0 : DO_UNSERIALIZE(ExprStmt);
807 : :
808 : : int len;
809 [ # # ]: 0 : if ( ! UNSERIALIZE(&len) )
810 : 0 : return false;
811 : :
812 [ # # ]: 0 : while ( len-- )
813 : : {
814 : 0 : Case* c = Case::Unserialize(info);
815 [ # # ]: 0 : if ( ! c )
816 : 0 : return false;
817 : :
818 : 0 : cases->append(c);
819 : : }
820 : :
821 : 0 : return true;
822 : : }
823 : :
824 : 134 : AddStmt::AddStmt(Expr* arg_e) : ExprStmt(STMT_ADD, arg_e)
825 : : {
826 [ - + # # ]: 134 : if ( ! e->CanAdd() )
827 : 0 : Error("illegal add statement");
828 : 134 : }
829 : :
830 : 0 : int AddStmt::IsPure() const
831 : : {
832 : 0 : return 0;
833 : : }
834 : :
835 : 279 : Val* AddStmt::Exec(Frame* f, stmt_flow_type& flow) const
836 : : {
837 : 279 : RegisterAccess();
838 : 279 : flow = FLOW_NEXT;
839 : 279 : e->Add(f);
840 : 279 : return 0;
841 : : }
842 : :
843 : :
844 : 0 : TraversalCode AddStmt::Traverse(TraversalCallback* cb) const
845 : : {
846 : 0 : TraversalCode tc = cb->PreStmt(this);
847 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
848 : :
849 : : // Argument is stored in base class's "e" field.
850 : 0 : tc = e->Traverse(cb);
851 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
852 : :
853 : 0 : tc = cb->PostStmt(this);
854 [ # # ][ # # ]: 0 : HANDLE_TC_STMT_POST(tc);
855 : : }
856 : :
857 : 3 : IMPLEMENT_SERIAL(AddStmt, SER_ADD_STMT);
858 : :
859 : 0 : bool AddStmt::DoSerialize(SerialInfo* info) const
860 : : {
861 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_ADD_STMT, ExprStmt);
862 : 0 : return true;
863 : : }
864 : :
865 : 0 : bool AddStmt::DoUnserialize(UnserialInfo* info)
866 : : {
867 [ # # ]: 0 : DO_UNSERIALIZE(ExprStmt);
868 : 0 : return true;
869 : : }
870 : :
871 : 141 : DelStmt::DelStmt(Expr* arg_e) : ExprStmt(STMT_DELETE, arg_e)
872 : : {
873 [ - + # # ]: 141 : if ( ! e->CanDel() )
874 : 0 : Error("illegal delete statement");
875 : 141 : }
876 : :
877 : 0 : int DelStmt::IsPure() const
878 : : {
879 : 0 : return 0;
880 : : }
881 : :
882 : 8295 : Val* DelStmt::Exec(Frame* f, stmt_flow_type& flow) const
883 : : {
884 : 8295 : RegisterAccess();
885 : 8295 : flow = FLOW_NEXT;
886 : 8295 : e->Delete(f);
887 : 8295 : return 0;
888 : : }
889 : :
890 : 0 : TraversalCode DelStmt::Traverse(TraversalCallback* cb) const
891 : : {
892 : 0 : TraversalCode tc = cb->PreStmt(this);
893 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
894 : :
895 : : // Argument is stored in base class's "e" field.
896 : 0 : tc = e->Traverse(cb);
897 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
898 : :
899 : 0 : tc = cb->PostStmt(this);
900 [ # # ][ # # ]: 0 : HANDLE_TC_STMT_POST(tc);
901 : : }
902 : :
903 : 3 : IMPLEMENT_SERIAL(DelStmt, SER_DEL_STMT);
904 : :
905 : 0 : bool DelStmt::DoSerialize(SerialInfo* info) const
906 : : {
907 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_DEL_STMT, ExprStmt);
908 : 0 : return true;
909 : : }
910 : :
911 : 0 : bool DelStmt::DoUnserialize(UnserialInfo* info)
912 : : {
913 [ # # ]: 0 : DO_UNSERIALIZE(ExprStmt);
914 : 0 : return true;
915 : : }
916 : :
917 : 78 : EventStmt::EventStmt(EventExpr* arg_e) : ExprStmt(STMT_EVENT, arg_e)
918 : : {
919 : 78 : event_expr = arg_e;
920 : 78 : }
921 : :
922 : 3360 : Val* EventStmt::Exec(Frame* f, stmt_flow_type& flow) const
923 : : {
924 : 3360 : RegisterAccess();
925 : 3360 : val_list* args = eval_list(f, event_expr->Args());
926 : :
927 [ + - ]: 3360 : if ( args )
928 : 3360 : mgr.QueueEvent(event_expr->Handler(), args);
929 : :
930 : 3360 : flow = FLOW_NEXT;
931 : :
932 : 3360 : return 0;
933 : : }
934 : :
935 : 0 : TraversalCode EventStmt::Traverse(TraversalCallback* cb) const
936 : : {
937 : 0 : TraversalCode tc = cb->PreStmt(this);
938 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
939 : :
940 : : // Event is stored in base class's "e" field.
941 : 0 : tc = e->Traverse(cb);
942 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
943 : :
944 : 0 : tc = cb->PostStmt(this);
945 [ # # ][ # # ]: 0 : HANDLE_TC_STMT_POST(tc);
946 : : }
947 : :
948 : 3 : IMPLEMENT_SERIAL(EventStmt, SER_EVENT_STMT);
949 : :
950 : 0 : bool EventStmt::DoSerialize(SerialInfo* info) const
951 : : {
952 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_EVENT_STMT, ExprStmt);
953 : 0 : return event_expr->Serialize(info);
954 : : }
955 : :
956 : 0 : bool EventStmt::DoUnserialize(UnserialInfo* info)
957 : : {
958 [ # # ]: 0 : DO_UNSERIALIZE(ExprStmt);
959 : :
960 : 0 : event_expr = (EventExpr*) Expr::Unserialize(info, EXPR_EVENT);
961 : 0 : return event_expr != 0;
962 : : }
963 : :
964 : 123 : ForStmt::ForStmt(id_list* arg_loop_vars, Expr* loop_expr)
965 : 123 : : ExprStmt(STMT_FOR, loop_expr)
966 : : {
967 : 123 : loop_vars = arg_loop_vars;
968 : 123 : body = 0;
969 : :
970 [ + + # # ]: 123 : if ( e->Type()->Tag() == TYPE_TABLE )
971 : : {
972 : 115 : const type_list* indices = e->Type()->AsTableType()->IndexTypes();
973 [ - + # # ]: 115 : if ( indices->length() != loop_vars->length() )
974 : 0 : e->Error("wrong index size");
975 : :
976 [ + + ][ # # ]: 231 : for ( int i = 0; i < indices->length(); i++ )
977 : : {
978 : 116 : BroType* ind_type = (*indices)[i]->Ref();
979 : :
980 [ + + # # ]: 116 : if ( (*loop_vars)[i]->Type() )
981 : : {
982 [ - + ][ # # ]: 16 : if ( ! same_type((*loop_vars)[i]->Type(), ind_type) )
983 : 16 : (*loop_vars)[i]->Type()->Error("type clash in iteration", ind_type);
984 : : }
985 : :
986 : : else
987 : : {
988 : : delete add_local((*loop_vars)[i],
989 : : ind_type->Ref(), INIT_NONE,
990 [ + - ][ # # ]: 100 : 0, 0, VAR_REGULAR);
991 : : }
992 : : }
993 : : }
994 : :
995 [ + + ][ # # ]: 8 : else if ( e->Type()->Tag() == TYPE_VECTOR )
996 : : {
997 [ - + ][ # # ]: 5 : if ( loop_vars->length() != 1 )
998 : : {
999 : 0 : e->Error("iterating over a vector requires only a single index type");
1000 : 0 : return;
1001 : : }
1002 : :
1003 : 5 : BroType* t = (*loop_vars)[0]->Type();
1004 [ + + # # ]: 5 : if ( ! t )
1005 : : delete add_local((*loop_vars)[0], base_type(TYPE_INT),
1006 [ + - ][ # # ]: 4 : INIT_NONE, 0, 0, VAR_REGULAR);
1007 : :
1008 [ + - ][ - + ]: 1 : else if ( ! IsIntegral(t->Tag()) )
[ # # ][ - + ]
[ # # ][ # # ]
[ # # ][ # # ]
1009 : : {
1010 : 0 : e->Error("vector index in \"for\" loop must be integral");
1011 : 5 : return;
1012 : : }
1013 : : }
1014 : :
1015 [ + - ][ # # ]: 3 : else if ( e->Type()->Tag() == TYPE_STRING )
1016 : : {
1017 [ - + ][ # # ]: 3 : if ( loop_vars->length() != 1 )
1018 : : {
1019 : 0 : e->Error("iterating over a string requires only a single index type");
1020 : 0 : return;
1021 : : }
1022 : :
1023 : 3 : BroType* t = (*loop_vars)[0]->Type();
1024 [ + - # # ]: 3 : if ( ! t )
1025 : : delete add_local((*loop_vars)[0],
1026 : : base_type(TYPE_STRING),
1027 [ + - ][ # # ]: 3 : INIT_NONE, 0, 0, VAR_REGULAR);
1028 : :
1029 [ # # ][ # # ]: 0 : else if ( t->Tag() != TYPE_STRING )
1030 : : {
1031 : 0 : e->Error("string index in \"for\" loop must be string");
1032 : 3 : return;
1033 : : }
1034 : : }
1035 : : else
1036 : 123 : e->Error("target to iterate over must be a table, set, vector, or string");
1037 : 123 : }
1038 : :
1039 : 0 : ForStmt::~ForStmt()
1040 : : {
1041 [ # # ][ # # ]: 0 : loop_over_list(*loop_vars, i)
[ # # ]
1042 : 0 : Unref((*loop_vars)[i]);
1043 [ # # ][ # # ]: 0 : delete loop_vars;
[ # # ]
1044 : :
1045 : 0 : Unref(body);
1046 [ # # ][ # # ]: 0 : }
[ # # ]
1047 : :
1048 : 23757 : Val* ForStmt::DoExec(Frame* f, Val* v, stmt_flow_type& flow) const
1049 : : {
1050 : 23757 : Val* ret = 0;
1051 : :
1052 [ + + ]: 23757 : if ( v->Type()->Tag() == TYPE_TABLE )
1053 : : {
1054 : 314 : TableVal* tv = v->AsTableVal();
1055 : 314 : const PDict(TableEntryVal)* loop_vals = tv->AsTable();
1056 : :
1057 : : HashKey* k;
1058 : : TableEntryVal* iter_val;
1059 : 314 : IterCookie* c = loop_vals->InitForIteration();
1060 [ + + ]: 346 : while ( (iter_val = loop_vals->NextEntry(k, c)) )
1061 : : {
1062 : 32 : ListVal* ind_lv = tv->RecoverIndex(k);
1063 [ + - ]: 32 : delete k;
1064 : :
1065 [ + + ]: 64 : for ( int i = 0; i < ind_lv->Length(); i++ )
1066 : 32 : f->SetElement((*loop_vars)[i]->Offset(), ind_lv->Index(i)->Ref());
1067 : 32 : Unref(ind_lv);
1068 : :
1069 : 32 : flow = FLOW_NEXT;
1070 : 32 : ret = body->Exec(f, flow);
1071 : :
1072 [ + - - + ]: 32 : if ( flow == FLOW_BREAK || flow == FLOW_RETURN )
1073 : : {
1074 : : // If we broke or returned from inside a for loop,
1075 : : // the cookie may still exist.
1076 : 0 : loop_vals->StopIteration(c);
1077 : 0 : break;
1078 : : }
1079 : : }
1080 : : }
1081 : :
1082 [ + + ]: 23443 : else if ( v->Type()->Tag() == TYPE_VECTOR )
1083 : : {
1084 : 1379 : VectorVal* vv = v->AsVectorVal();
1085 : :
1086 [ + + ]: 24822 : for ( int i = 0; i <= int(vv->Size()); ++i )
1087 : : {
1088 : : // Skip unassigned vector indices.
1089 [ + + ]: 23443 : if ( ! vv->Lookup(i) )
1090 : 1379 : continue;
1091 : :
1092 : : // Set the loop variable to the current index, and make
1093 : : // another pass over the loop body.
1094 : : f->SetElement((*loop_vars)[0]->Offset(),
1095 : 22064 : new Val(i, TYPE_INT));
1096 : 22064 : flow = FLOW_NEXT;
1097 : 22064 : ret = body->Exec(f, flow);
1098 : :
1099 [ + - - + ]: 22064 : if ( flow == FLOW_BREAK || flow == FLOW_RETURN )
1100 : 0 : break;
1101 : : }
1102 : : }
1103 [ + - ]: 22064 : else if ( v->Type()->Tag() == TYPE_STRING )
1104 : : {
1105 : 22064 : StringVal* sval = v->AsStringVal();
1106 : :
1107 [ + + ]: 44128 : for ( int i = 0; i < sval->Len(); ++i )
1108 : : {
1109 : : f->SetElement((*loop_vars)[0]->Offset(),
1110 : 22064 : new StringVal(1, (const char*) sval->Bytes() + i));
1111 : 22064 : flow = FLOW_NEXT;
1112 : 22064 : ret = body->Exec(f, flow);
1113 : :
1114 [ + - - + ]: 22064 : if ( flow == FLOW_BREAK || flow == FLOW_RETURN )
1115 : 0 : break;
1116 : : }
1117 : : }
1118 : :
1119 : : else
1120 : 0 : e->Error("Invalid type in for-loop execution");
1121 : :
1122 [ - + ]: 23757 : if ( flow == FLOW_LOOP )
1123 : 0 : flow = FLOW_NEXT; // last iteration exited with a "next"
1124 : :
1125 [ - + ]: 23757 : if ( flow == FLOW_BREAK )
1126 : 0 : flow = FLOW_NEXT; // we've now finished the "break"
1127 : :
1128 : 23757 : return ret;
1129 : : }
1130 : :
1131 : 0 : Stmt* ForStmt::DoSimplify()
1132 : : {
1133 : 0 : body = simplify_stmt(body);
1134 : :
1135 [ # # ]: 0 : if ( e->IsConst() )
1136 : : {
1137 : 0 : const PDict(TableEntryVal)* vt = e->ExprVal()->AsTable();
1138 : :
1139 [ # # ]: 0 : if ( vt->Length() == 0 )
1140 : 0 : return new NullStmt();
1141 : : }
1142 : :
1143 : 0 : return this;
1144 : : }
1145 : :
1146 : 0 : int ForStmt::IsPure() const
1147 : : {
1148 [ # # ][ # # ]: 0 : return e->IsPure() && body->IsPure();
1149 : : }
1150 : :
1151 : 0 : void ForStmt::Describe(ODesc* d) const
1152 : : {
1153 : 0 : Stmt::Describe(d);
1154 : :
1155 [ # # ]: 0 : if ( d->IsReadable() )
1156 : 0 : d->Add("(");
1157 : :
1158 [ # # ]: 0 : if ( loop_vars->length() )
1159 : 0 : d->Add("[");
1160 : :
1161 [ # # ]: 0 : loop_over_list(*loop_vars, i)
1162 : : {
1163 : 0 : (*loop_vars)[i]->Describe(d);
1164 [ # # ]: 0 : if ( i > 0 )
1165 : 0 : d->Add(",");
1166 : : }
1167 : :
1168 [ # # ]: 0 : if ( loop_vars->length() )
1169 : 0 : d->Add("]");
1170 : :
1171 [ # # ]: 0 : if ( d->IsReadable() )
1172 : 0 : d->Add(" in ");
1173 : :
1174 : 0 : e->Describe(d);
1175 : :
1176 [ # # ]: 0 : if ( d->IsReadable() )
1177 : 0 : d->Add(")");
1178 : :
1179 : 0 : d->SP();
1180 : :
1181 : 0 : d->PushIndent();
1182 : 0 : body->AccessStats(d);
1183 : 0 : body->Describe(d);
1184 : 0 : d->PopIndent();
1185 : 0 : }
1186 : :
1187 : 0 : TraversalCode ForStmt::Traverse(TraversalCallback* cb) const
1188 : : {
1189 : 0 : TraversalCode tc = cb->PreStmt(this);
1190 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
1191 : :
1192 [ # # ]: 0 : loop_over_list(*loop_vars, i)
1193 : : {
1194 : 0 : tc = (*loop_vars)[i]->Traverse(cb);
1195 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
1196 : : }
1197 : :
1198 : 0 : tc = LoopExpr()->Traverse(cb);
1199 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
1200 : :
1201 : 0 : tc = LoopBody()->Traverse(cb);
1202 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
1203 : :
1204 : 0 : tc = cb->PostStmt(this);
1205 [ # # ][ # # ]: 0 : HANDLE_TC_STMT_POST(tc);
1206 : : }
1207 : :
1208 : 3 : IMPLEMENT_SERIAL(ForStmt, SER_FOR_STMT);
1209 : :
1210 : 0 : bool ForStmt::DoSerialize(SerialInfo* info) const
1211 : : {
1212 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_FOR_STMT, ExprStmt);
1213 : :
1214 [ # # ]: 0 : if ( ! SERIALIZE(loop_vars->length()) )
1215 : 0 : return false;
1216 : :
1217 [ # # ]: 0 : loop_over_list((*loop_vars), i)
1218 : : {
1219 [ # # ]: 0 : if ( ! (*loop_vars)[i]->Serialize(info) )
1220 : 0 : return false;
1221 : : }
1222 : :
1223 : 0 : return body->Serialize(info);
1224 : : }
1225 : :
1226 : 0 : bool ForStmt::DoUnserialize(UnserialInfo* info)
1227 : : {
1228 [ # # ]: 0 : DO_UNSERIALIZE(ExprStmt);
1229 : :
1230 : : int len;
1231 [ # # ]: 0 : if ( ! UNSERIALIZE(&len) )
1232 : 0 : return false;
1233 : :
1234 : 0 : loop_vars = new id_list;
1235 : :
1236 [ # # ]: 0 : while ( len-- )
1237 : : {
1238 : 0 : ID* id = ID::Unserialize(info);
1239 [ # # ]: 0 : if ( ! id )
1240 : 0 : return false;
1241 : :
1242 : 0 : loop_vars->append(id);
1243 : : }
1244 : :
1245 : 0 : body = Stmt::Unserialize(info);
1246 : 0 : return body != 0;
1247 : : }
1248 : :
1249 : 0 : Val* NextStmt::Exec(Frame* /* f */, stmt_flow_type& flow) const
1250 : : {
1251 : 0 : RegisterAccess();
1252 : 0 : flow = FLOW_LOOP;
1253 : 0 : return 0;
1254 : : }
1255 : :
1256 : 0 : int NextStmt::IsPure() const
1257 : : {
1258 : 0 : return 1;
1259 : : }
1260 : :
1261 : 0 : void NextStmt::Describe(ODesc* d) const
1262 : : {
1263 : 0 : Stmt::Describe(d);
1264 : 0 : Stmt::DescribeDone(d);
1265 : 0 : }
1266 : :
1267 : 0 : TraversalCode NextStmt::Traverse(TraversalCallback* cb) const
1268 : : {
1269 : 0 : TraversalCode tc = cb->PreStmt(this);
1270 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
1271 : :
1272 : 0 : tc = cb->PostStmt(this);
1273 [ # # ][ # # ]: 0 : HANDLE_TC_STMT_POST(tc);
1274 : : }
1275 : :
1276 : 3 : IMPLEMENT_SERIAL(NextStmt, SER_NEXT_STMT);
1277 : :
1278 : 0 : bool NextStmt::DoSerialize(SerialInfo* info) const
1279 : : {
1280 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_NEXT_STMT, Stmt);
1281 : 0 : return true;
1282 : : }
1283 : :
1284 : 0 : bool NextStmt::DoUnserialize(UnserialInfo* info)
1285 : : {
1286 [ # # ]: 0 : DO_UNSERIALIZE(Stmt);
1287 : 0 : return true;
1288 : : }
1289 : :
1290 : 0 : Val* BreakStmt::Exec(Frame* /* f */, stmt_flow_type& flow) const
1291 : : {
1292 : 0 : RegisterAccess();
1293 : 0 : flow = FLOW_BREAK;
1294 : 0 : return 0;
1295 : : }
1296 : :
1297 : 0 : int BreakStmt::IsPure() const
1298 : : {
1299 : 0 : return 1;
1300 : : }
1301 : :
1302 : 0 : void BreakStmt::Describe(ODesc* d) const
1303 : : {
1304 : 0 : Stmt::Describe(d);
1305 : 0 : Stmt::DescribeDone(d);
1306 : 0 : }
1307 : :
1308 : 0 : TraversalCode BreakStmt::Traverse(TraversalCallback* cb) const
1309 : : {
1310 : 0 : TraversalCode tc = cb->PreStmt(this);
1311 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
1312 : :
1313 : 0 : tc = cb->PostStmt(this);
1314 [ # # ][ # # ]: 0 : HANDLE_TC_STMT_POST(tc);
1315 : : }
1316 : :
1317 : 3 : IMPLEMENT_SERIAL(BreakStmt, SER_BREAK_STMT);
1318 : :
1319 : 0 : bool BreakStmt::DoSerialize(SerialInfo* info) const
1320 : : {
1321 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_BREAK_STMT, Stmt);
1322 : 0 : return true;
1323 : : }
1324 : :
1325 : 0 : bool BreakStmt::DoUnserialize(UnserialInfo* info)
1326 : : {
1327 [ # # ]: 0 : DO_UNSERIALIZE(Stmt);
1328 : 0 : return true;
1329 : : }
1330 : :
1331 : 816 : ReturnStmt::ReturnStmt(Expr* arg_e) : ExprStmt(STMT_RETURN, arg_e)
1332 : : {
1333 : 816 : Scope* s = current_scope();
1334 : :
1335 [ + - - + ]: 816 : if ( ! s || ! s->ScopeID() )
[ - + # # ]
[ # # ][ # # ]
1336 : : {
1337 : 0 : Error("return statement outside of function/event");
1338 : 0 : return;
1339 : : }
1340 : :
1341 : 816 : FuncType* ft = s->ScopeID()->Type()->AsFuncType();
1342 : 816 : BroType* yt = ft->YieldType();
1343 : :
1344 [ + + # # ]: 816 : if ( s->ScopeID()->DoInferReturnType() )
1345 : : {
1346 [ + - ][ # # ]: 5 : if ( e )
1347 : : {
1348 : 5 : ft->SetYieldType(e->Type());
1349 : 5 : s->ScopeID()->SetInferReturnType(false);
1350 : : }
1351 : : }
1352 : :
1353 [ + + ][ + + ]: 811 : else if ( ! yt || yt->Tag() == TYPE_VOID )
[ + + ][ # # ]
[ # # ][ # # ]
1354 : : {
1355 [ - + ][ # # ]: 203 : if ( e )
1356 : 203 : Error("return statement cannot have an expression");
1357 : : }
1358 : :
1359 [ - + ][ # # ]: 608 : else if ( ! e )
1360 : 0 : Error("return statement needs expression");
1361 : :
1362 : : else
1363 : 816 : (void) check_and_promote_expr(e, yt);
1364 : 816 : }
1365 : :
1366 : 70733 : Val* ReturnStmt::Exec(Frame* f, stmt_flow_type& flow) const
1367 : : {
1368 : 70733 : RegisterAccess();
1369 : 70733 : flow = FLOW_RETURN;
1370 : :
1371 [ + + ]: 70733 : if ( e )
1372 : 62147 : return e->Eval(f);
1373 : : else
1374 : 70733 : return 0;
1375 : : }
1376 : :
1377 : 0 : void ReturnStmt::Describe(ODesc* d) const
1378 : : {
1379 : 0 : Stmt::Describe(d);
1380 [ # # ]: 0 : if ( ! d->IsReadable() )
1381 : 0 : d->Add(e != 0);
1382 : :
1383 [ # # ]: 0 : if ( e )
1384 : : {
1385 [ # # ]: 0 : if ( ! d->IsBinary() )
1386 : 0 : d->Add("(");
1387 : 0 : e->Describe(d);
1388 [ # # ]: 0 : if ( ! d->IsBinary() )
1389 : 0 : d->Add(")");
1390 : : }
1391 : :
1392 : 0 : DescribeDone(d);
1393 : 0 : }
1394 : :
1395 : 3 : IMPLEMENT_SERIAL(ReturnStmt, SER_RETURN_STMT);
1396 : :
1397 : 0 : bool ReturnStmt::DoSerialize(SerialInfo* info) const
1398 : : {
1399 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_RETURN_STMT, ExprStmt);
1400 : 0 : return true;
1401 : : }
1402 : :
1403 : 0 : bool ReturnStmt::DoUnserialize(UnserialInfo* info)
1404 : : {
1405 [ # # ]: 0 : DO_UNSERIALIZE(ExprStmt);
1406 : 0 : return true;
1407 : : }
1408 : :
1409 : 2002 : StmtList::StmtList() : Stmt(STMT_LIST)
1410 : : {
1411 : 2002 : }
1412 : :
1413 : 1 : StmtList::~StmtList()
1414 : : {
1415 [ + + ][ # # ]: 2 : loop_over_list(stmts, i)
[ # # ]
1416 : 1 : Unref(stmts[i]);
1417 [ + - ][ # # ]: 1 : }
[ # # ]
1418 : :
1419 : 154589 : Val* StmtList::Exec(Frame* f, stmt_flow_type& flow) const
1420 : : {
1421 : 154589 : RegisterAccess();
1422 : 154589 : flow = FLOW_NEXT;
1423 : :
1424 [ + + ]: 532811 : loop_over_list(stmts, i)
1425 : : {
1426 : 460442 : f->SetNextStmt(stmts[i]);
1427 : :
1428 : 460442 : if ( ! pre_execute_stmt(stmts[i], f) )
1429 : : { // ### Abort or something
1430 : : }
1431 : :
1432 : 460442 : Val* result = stmts[i]->Exec(f, flow);
1433 : :
1434 : 460442 : if ( ! post_execute_stmt(stmts[i], f, result, &flow) )
1435 : : { // ### Abort or something
1436 : : }
1437 : :
1438 [ + + + - ]: 460442 : if ( flow != FLOW_NEXT || result || f->HasDelayed() )
[ - + ][ + + ]
1439 : 82220 : return result;
1440 : : }
1441 : :
1442 : 154589 : return 0;
1443 : : }
1444 : :
1445 : 0 : Stmt* StmtList::Simplify()
1446 : : {
1447 [ # # ]: 0 : if ( stmts.length() == 0 )
1448 : 0 : return new NullStmt();
1449 : :
1450 [ # # ]: 0 : if ( stmts.length() == 1 )
1451 : 0 : return stmts[0]->Ref();
1452 : :
1453 [ # # ]: 0 : loop_over_list(stmts, i)
1454 : 0 : stmts.replace(i, simplify_stmt(stmts[i]));
1455 : :
1456 : 0 : return this;
1457 : : }
1458 : :
1459 : 0 : int StmtList::IsPure() const
1460 : : {
1461 [ # # ]: 0 : loop_over_list(stmts, i)
1462 [ # # ]: 0 : if ( ! stmts[i]->IsPure() )
1463 : 0 : return 0;
1464 : 0 : return 1;
1465 : : }
1466 : :
1467 : 0 : void StmtList::Describe(ODesc* d) const
1468 : : {
1469 [ # # ]: 0 : if ( ! d->IsReadable() )
1470 : : {
1471 : 0 : AddTag(d);
1472 : 0 : d->AddCount(stmts.length());
1473 : : }
1474 : :
1475 [ # # ]: 0 : if ( stmts.length() == 0 )
1476 : 0 : DescribeDone(d);
1477 : :
1478 : : else
1479 : : {
1480 [ # # ]: 0 : if ( ! d->IsBinary() )
1481 : : {
1482 : 0 : d->Add("{ ");
1483 : 0 : d->NL();
1484 : : }
1485 : :
1486 [ # # ]: 0 : loop_over_list(stmts, i)
1487 : : {
1488 : 0 : stmts[i]->Describe(d);
1489 : 0 : d->NL();
1490 : : }
1491 : :
1492 [ # # ]: 0 : if ( ! d->IsBinary() )
1493 : 0 : d->Add("}");
1494 : : }
1495 : 0 : }
1496 : :
1497 : 0 : TraversalCode StmtList::Traverse(TraversalCallback* cb) const
1498 : : {
1499 : 0 : TraversalCode tc = cb->PreStmt(this);
1500 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
1501 : :
1502 [ # # ]: 0 : loop_over_list(stmts, i)
1503 : : {
1504 : 0 : tc = stmts[i]->Traverse(cb);
1505 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
1506 : : }
1507 : :
1508 : 0 : tc = cb->PostStmt(this);
1509 [ # # ][ # # ]: 0 : HANDLE_TC_STMT_POST(tc);
1510 : : }
1511 : :
1512 : 3 : IMPLEMENT_SERIAL(StmtList, SER_STMT_LIST);
1513 : :
1514 : 0 : bool StmtList::DoSerialize(SerialInfo* info) const
1515 : : {
1516 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_STMT_LIST, Stmt);
1517 : :
1518 [ # # ]: 0 : if ( ! SERIALIZE(stmts.length()) )
1519 : 0 : return false;
1520 : :
1521 [ # # ]: 0 : loop_over_list(stmts, i)
1522 [ # # ]: 0 : if ( ! stmts[i]->Serialize(info) )
1523 : 0 : return false;
1524 : :
1525 : 0 : return true;
1526 : : }
1527 : :
1528 : 0 : bool StmtList::DoUnserialize(UnserialInfo* info)
1529 : : {
1530 [ # # ]: 0 : DO_UNSERIALIZE(Stmt);
1531 : :
1532 : : int len;
1533 [ # # ]: 0 : if ( ! UNSERIALIZE(&len) )
1534 : 0 : return false;
1535 : :
1536 [ # # ]: 0 : while ( len-- )
1537 : : {
1538 : 0 : Stmt* stmt = Stmt::Unserialize(info);
1539 [ # # ]: 0 : if ( ! stmt )
1540 : 0 : return false;
1541 : :
1542 : 0 : stmts.append(stmt);
1543 : : }
1544 : :
1545 : 0 : return true;
1546 : : }
1547 : :
1548 : :
1549 : 0 : Val* EventBodyList::Exec(Frame* f, stmt_flow_type& flow) const
1550 : : {
1551 : 0 : RegisterAccess();
1552 : 0 : flow = FLOW_NEXT;
1553 : :
1554 [ # # ]: 0 : loop_over_list(stmts, i)
1555 : : {
1556 : 0 : f->SetNextStmt(stmts[i]);
1557 : :
1558 : : // Ignore the return value, since there shouldn't be
1559 : : // any; and ignore the flow, since we still execute
1560 : : // all of the event bodies even if one of them does
1561 : : // a FLOW_RETURN.
1562 : 0 : if ( ! pre_execute_stmt(stmts[i], f) )
1563 : : { // ### Abort or something
1564 : : }
1565 : :
1566 : 0 : Val* result = stmts[i]->Exec(f, flow);
1567 : :
1568 : 0 : if ( ! post_execute_stmt(stmts[i], f, result, &flow) )
1569 : : { // ### Abort or something
1570 : : }
1571 : : }
1572 : :
1573 : : // Simulate a return so the hooks operate properly.
1574 : 0 : stmt_flow_type ft = FLOW_RETURN;
1575 : 0 : (void) post_execute_stmt(f->GetNextStmt(), f, 0, &ft);
1576 : :
1577 : 0 : return 0;
1578 : : }
1579 : :
1580 : 0 : Stmt* EventBodyList::Simplify()
1581 : : {
1582 [ # # ]: 0 : if ( stmts.length() <= 1 )
1583 : : // Don't simplify these, we don't want to lose our
1584 : : // "execute even across returns" property.
1585 : 0 : return this;
1586 : :
1587 : : else
1588 : 0 : return StmtList::Simplify();
1589 : : }
1590 : :
1591 : 0 : void EventBodyList::Describe(ODesc* d) const
1592 : : {
1593 [ # # ][ # # ]: 0 : if ( d->IsReadable() && stmts.length() > 0 )
[ # # ]
1594 : : {
1595 [ # # ]: 0 : loop_over_list(stmts, i)
1596 : : {
1597 [ # # ]: 0 : if ( ! d->IsBinary() )
1598 : : {
1599 : 0 : d->Add("{");
1600 : 0 : d->PushIndent();
1601 : 0 : stmts[i]->AccessStats(d);
1602 : : }
1603 : :
1604 : 0 : stmts[i]->Describe(d);
1605 : :
1606 [ # # ]: 0 : if ( ! d->IsBinary() )
1607 : : {
1608 : 0 : d->Add("}");
1609 : 0 : d->PopIndent();
1610 : : }
1611 : : }
1612 : : }
1613 : :
1614 : : else
1615 : 0 : StmtList::Describe(d);
1616 : 0 : }
1617 : :
1618 : 3 : IMPLEMENT_SERIAL(EventBodyList, SER_EVENT_BODY_LIST);
1619 : :
1620 : 0 : bool EventBodyList::DoSerialize(SerialInfo* info) const
1621 : : {
1622 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_EVENT_BODY_LIST, StmtList);
1623 : 0 : return SERIALIZE(topmost);
1624 : : }
1625 : :
1626 : 0 : bool EventBodyList::DoUnserialize(UnserialInfo* info)
1627 : : {
1628 [ # # ]: 0 : DO_UNSERIALIZE(StmtList);
1629 : 0 : return UNSERIALIZE(&topmost);
1630 : : }
1631 : :
1632 : 0 : InitStmt::~InitStmt()
1633 : : {
1634 [ # # ][ # # ]: 0 : loop_over_list(*inits, i)
[ # # ]
1635 : 0 : Unref((*inits)[i]);
1636 : :
1637 [ # # ][ # # ]: 0 : delete inits;
[ # # ]
1638 [ # # ][ # # ]: 0 : }
[ # # ]
1639 : :
1640 : 5771 : Val* InitStmt::Exec(Frame* f, stmt_flow_type& flow) const
1641 : : {
1642 : 5771 : RegisterAccess();
1643 : 5771 : flow = FLOW_NEXT;
1644 : :
1645 [ + + ]: 11842 : loop_over_list(*inits, i)
1646 : : {
1647 : 6071 : ID* aggr = (*inits)[i];
1648 : 6071 : BroType* t = aggr->Type();
1649 : :
1650 : : Val* v;
1651 [ + + ]: 6071 : if ( t->Tag() == TYPE_RECORD )
1652 : 3905 : v = new RecordVal(t->AsRecordType());
1653 [ - + ]: 2166 : else if ( aggr->Type()->Tag() == TYPE_VECTOR )
1654 : 0 : v = new VectorVal(t->AsVectorType());
1655 : : else
1656 : 2166 : v = new TableVal(t->AsTableType(), aggr->Attrs());
1657 : :
1658 : 6071 : f->SetElement(aggr->Offset(), v);
1659 : : }
1660 : :
1661 : 5771 : return 0;
1662 : : }
1663 : :
1664 : 0 : void InitStmt::Describe(ODesc* d) const
1665 : : {
1666 : 0 : AddTag(d);
1667 : :
1668 [ # # ]: 0 : if ( ! d->IsReadable() )
1669 : 0 : d->AddCount(inits->length());
1670 : :
1671 [ # # ]: 0 : loop_over_list(*inits, i)
1672 : : {
1673 [ # # ][ # # ]: 0 : if ( ! d->IsBinary() && i > 0 )
[ # # ]
1674 : 0 : d->AddSP(",");
1675 : :
1676 : 0 : (*inits)[i]->Describe(d);
1677 : : }
1678 : :
1679 : 0 : DescribeDone(d);
1680 : 0 : }
1681 : :
1682 : 0 : TraversalCode InitStmt::Traverse(TraversalCallback* cb) const
1683 : : {
1684 : 0 : TraversalCode tc = cb->PreStmt(this);
1685 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
1686 : :
1687 [ # # ]: 0 : loop_over_list(*inits, i)
1688 : : {
1689 : 0 : tc = (*inits)[i]->Traverse(cb);
1690 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
1691 : : }
1692 : :
1693 : 0 : tc = cb->PostStmt(this);
1694 [ # # ][ # # ]: 0 : HANDLE_TC_STMT_POST(tc);
1695 : : }
1696 : :
1697 : 3 : IMPLEMENT_SERIAL(InitStmt, SER_INIT_STMT);
1698 : :
1699 : 0 : bool InitStmt::DoSerialize(SerialInfo* info) const
1700 : : {
1701 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_INIT_STMT, Stmt);
1702 : :
1703 [ # # ]: 0 : if ( ! SERIALIZE(inits->length()) )
1704 : 0 : return false;
1705 : :
1706 [ # # ]: 0 : loop_over_list((*inits), i)
1707 : : {
1708 [ # # ]: 0 : if ( ! (*inits)[i]->Serialize(info) )
1709 : 0 : return false;
1710 : : }
1711 : :
1712 : 0 : return true;
1713 : : }
1714 : :
1715 : 0 : bool InitStmt::DoUnserialize(UnserialInfo* info)
1716 : : {
1717 [ # # ]: 0 : DO_UNSERIALIZE(Stmt);
1718 : :
1719 : : int len;
1720 [ # # ]: 0 : if ( ! UNSERIALIZE(&len) )
1721 : 0 : return false;
1722 : :
1723 : 0 : inits = new id_list;
1724 : :
1725 [ # # ]: 0 : while ( len-- )
1726 : : {
1727 : 0 : ID* id = ID::Unserialize(info);
1728 [ # # ]: 0 : if ( ! id )
1729 : 0 : return false;
1730 : 0 : inits->append(id);
1731 : : }
1732 : 0 : return true;
1733 : : }
1734 : :
1735 : :
1736 : 84462 : Val* NullStmt::Exec(Frame* /* f */, stmt_flow_type& flow) const
1737 : : {
1738 : 84462 : RegisterAccess();
1739 : 84462 : flow = FLOW_NEXT;
1740 : 84462 : return 0;
1741 : : }
1742 : :
1743 : 0 : int NullStmt::IsPure() const
1744 : : {
1745 : 0 : return 1;
1746 : : }
1747 : :
1748 : 0 : void NullStmt::Describe(ODesc* d) const
1749 : : {
1750 [ # # ]: 0 : if ( d->IsReadable() )
1751 : 0 : DescribeDone(d);
1752 : : else
1753 : 0 : AddTag(d);
1754 : 0 : }
1755 : :
1756 : 0 : TraversalCode NullStmt::Traverse(TraversalCallback* cb) const
1757 : : {
1758 : 0 : TraversalCode tc = cb->PreStmt(this);
1759 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
1760 : :
1761 : 0 : tc = cb->PostStmt(this);
1762 [ # # ][ # # ]: 0 : HANDLE_TC_STMT_POST(tc);
1763 : : }
1764 : :
1765 : 3 : IMPLEMENT_SERIAL(NullStmt, SER_NULL_STMT);
1766 : :
1767 : 0 : bool NullStmt::DoSerialize(SerialInfo* info) const
1768 : : {
1769 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_NULL_STMT, Stmt);
1770 : 0 : return true;
1771 : : }
1772 : :
1773 : 0 : bool NullStmt::DoUnserialize(UnserialInfo* info)
1774 : : {
1775 [ # # ]: 0 : DO_UNSERIALIZE(Stmt);
1776 : 0 : return true;
1777 : : }
1778 : :
1779 : : WhenStmt::WhenStmt(Expr* arg_cond, Stmt* arg_s1, Stmt* arg_s2,
1780 : 2 : Expr* arg_timeout, bool arg_is_return)
1781 : 2 : : Stmt(STMT_WHEN)
1782 : : {
1783 [ - + # # ]: 2 : assert(arg_cond);
1784 [ - + ][ # # ]: 2 : assert(arg_s1);
1785 : :
1786 : 2 : cond = arg_cond;
1787 : 2 : s1 = arg_s1;
1788 : 2 : s2 = arg_s2;
1789 : 2 : timeout = arg_timeout;
1790 : 2 : is_return = arg_is_return;
1791 : :
1792 [ + - ][ - + ]: 2 : if ( ! cond->IsError() && ! IsBool(cond->Type()->Tag()) )
[ - + ][ # # ]
[ # # ][ # # ]
1793 : 0 : cond->Error("conditional in test must be boolean");
1794 : :
1795 [ + - ][ # # ]: 2 : if ( timeout )
1796 : : {
1797 [ + - ][ # # ]: 2 : if ( timeout->IsError() )
1798 : 2 : return;
1799 : :
1800 : 2 : TypeTag bt = timeout->Type()->Tag();
1801 [ + - - + # : 2 : if ( bt != TYPE_TIME && bt != TYPE_INTERVAL )
# ][ # # ]
1802 : 2 : cond->Error("when timeout requires a time or time interval");
1803 : : }
1804 : 0 : }
1805 : :
1806 : 0 : WhenStmt::~WhenStmt()
1807 : : {
1808 : 0 : Unref(cond);
1809 : 0 : Unref(s1);
1810 : 0 : Unref(s2);
1811 [ # # ][ # # ]: 0 : }
[ # # ]
1812 : :
1813 : 0 : Val* WhenStmt::Exec(Frame* f, stmt_flow_type& flow) const
1814 : : {
1815 : 0 : RegisterAccess();
1816 : 0 : flow = FLOW_NEXT;
1817 : :
1818 : 0 : ::Ref(cond);
1819 : 0 : ::Ref(s1);
1820 [ # # ]: 0 : if ( s2 )
1821 : 0 : ::Ref(s2);
1822 [ # # ]: 0 : if ( timeout )
1823 : 0 : ::Ref(timeout);
1824 : :
1825 : : // The new trigger object will take care of its own deletion.
1826 : 0 : new Trigger(cond, s1, s2, timeout, f, is_return, location);
1827 : :
1828 : 0 : return 0;
1829 : : }
1830 : :
1831 : 0 : Stmt* WhenStmt::Simplify()
1832 : : {
1833 : 0 : cond = simplify_expr(cond, SIMPLIFY_GENERAL);
1834 : 0 : s1 = simplify_stmt(s1);
1835 [ # # ]: 0 : if ( s2 )
1836 : 0 : s2 = simplify_stmt(s2);
1837 : :
1838 [ # # ]: 0 : if ( cond->IsPure() )
1839 : 0 : Warn("non-varying expression in when clause");
1840 : :
1841 : 0 : return this;
1842 : : }
1843 : :
1844 : 0 : int WhenStmt::IsPure() const
1845 : : {
1846 [ # # ][ # # ]: 0 : return cond->IsPure() && s1->IsPure() && (! s2 || s2->IsPure());
[ # # ][ # # ]
1847 : : }
1848 : :
1849 : 0 : void WhenStmt::Describe(ODesc* d) const
1850 : : {
1851 : 0 : Stmt::Describe(d);
1852 : :
1853 [ # # ]: 0 : if ( d->IsReadable() )
1854 : 0 : d->Add("(");
1855 : :
1856 : 0 : cond->Describe(d);
1857 : :
1858 [ # # ]: 0 : if ( d->IsReadable() )
1859 : 0 : d->Add(")");
1860 : :
1861 : 0 : d->SP();
1862 : 0 : d->PushIndent();
1863 : 0 : s1->AccessStats(d);
1864 : 0 : s1->Describe(d);
1865 : 0 : d->PopIndent();
1866 : :
1867 [ # # ]: 0 : if ( s2 )
1868 : : {
1869 [ # # ]: 0 : if ( d->IsReadable() )
1870 : : {
1871 : 0 : d->SP();
1872 : 0 : d->Add("timeout");
1873 : 0 : d->SP();
1874 : 0 : timeout->Describe(d);
1875 : 0 : d->SP();
1876 : 0 : d->PushIndent();
1877 : 0 : s2->AccessStats(d);
1878 : 0 : s2->Describe(d);
1879 : 0 : d->PopIndent();
1880 : : }
1881 : : else
1882 : 0 : s2->Describe(d);
1883 : : }
1884 : 0 : }
1885 : :
1886 : 0 : TraversalCode WhenStmt::Traverse(TraversalCallback* cb) const
1887 : : {
1888 : 0 : TraversalCode tc = cb->PreStmt(this);
1889 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
1890 : :
1891 : 0 : tc = cond->Traverse(cb);
1892 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
1893 : :
1894 : 0 : tc = s1->Traverse(cb);
1895 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
1896 : :
1897 [ # # ]: 0 : if ( s2 )
1898 : : {
1899 : 0 : tc = s2->Traverse(cb);
1900 [ # # # # ]: 0 : HANDLE_TC_STMT_PRE(tc);
1901 : : }
1902 : :
1903 : 0 : tc = cb->PostStmt(this);
1904 [ # # ][ # # ]: 0 : HANDLE_TC_STMT_POST(tc);
1905 : : }
1906 : :
1907 : 3 : IMPLEMENT_SERIAL(WhenStmt, SER_WHEN_STMT);
1908 : :
1909 : 0 : bool WhenStmt::DoSerialize(SerialInfo* info) const
1910 : : {
1911 [ # # ][ # # ]: 0 : DO_SERIALIZE(SER_WHEN_STMT, Stmt);
1912 : :
1913 [ # # ][ # # ]: 0 : if ( cond->Serialize(info) && s1->Serialize(info) )
[ # # ]
1914 : 0 : return false;
1915 : :
1916 [ # # ][ # # ]: 0 : SERIALIZE_OPTIONAL(s2);
[ # # ][ # # ]
[ # # ][ # # ]
1917 [ # # ][ # # ]: 0 : SERIALIZE_OPTIONAL(timeout);
[ # # ][ # # ]
[ # # ][ # # ]
1918 : :
1919 : 0 : return true;
1920 : : }
1921 : :
1922 : 0 : bool WhenStmt::DoUnserialize(UnserialInfo* info)
1923 : : {
1924 [ # # ]: 0 : DO_UNSERIALIZE(Stmt);
1925 : :
1926 : 0 : cond = Expr::Unserialize(info);
1927 [ # # ]: 0 : if ( ! cond )
1928 : 0 : return false;
1929 : :
1930 : 0 : s1 = Stmt::Unserialize(info);
1931 [ # # ]: 0 : if ( ! s1 )
1932 : 0 : return false;
1933 : :
1934 [ # # ][ # # ]: 0 : UNSERIALIZE_OPTIONAL(s2, Stmt::Unserialize(info));
[ # # ]
1935 [ # # ][ # # ]: 0 : UNSERIALIZE_OPTIONAL(timeout, Expr::Unserialize(info));
[ # # ]
1936 : :
1937 : 0 : return true;
1938 : : }
1939 : :
1940 : 0 : Stmt* simplify_stmt(Stmt* s)
1941 : : {
1942 [ # # ]: 0 : for ( Stmt* ss = s->Simplify(); ss != s; ss = s->Simplify() )
1943 : : {
1944 : 0 : Unref(s);
1945 : 0 : s = ss;
1946 : : }
1947 : :
1948 : 0 : return s;
1949 : : }
1950 : :
1951 : 0 : int same_stmt(const Stmt* s1, const Stmt* s2)
1952 : : {
1953 [ # # ]: 0 : if ( s1 == s2 )
1954 : 0 : return 1;
1955 : :
1956 [ # # ]: 0 : if ( s1->Tag() != s2->Tag() )
1957 : 0 : return 0;
1958 : :
1959 [ # # # # # : 0 : switch ( s1->Tag() ) {
# # # # # ]
1960 : : case STMT_ALARM:
1961 : : case STMT_PRINT:
1962 : : {
1963 : 0 : const ListExpr* l1 = ((const ExprListStmt*) s1)->ExprList();
1964 : 0 : const ListExpr* l2 = ((const ExprListStmt*) s2)->ExprList();
1965 : 0 : return same_expr(l1, l2);
1966 : : }
1967 : :
1968 : : case STMT_ADD:
1969 : : case STMT_DELETE:
1970 : : case STMT_RETURN:
1971 : : case STMT_EXPR:
1972 : : case STMT_EVENT:
1973 : : {
1974 : 0 : const ExprStmt* e1 = (const ExprStmt*) s1;
1975 : 0 : const ExprStmt* e2 = (const ExprStmt*) s2;
1976 : 0 : return same_expr(e1->StmtExpr(), e2->StmtExpr());
1977 : : }
1978 : :
1979 : : case STMT_FOR:
1980 : : {
1981 : 0 : const ForStmt* f1 = (const ForStmt*) s1;
1982 : 0 : const ForStmt* f2 = (const ForStmt*) s2;
1983 : :
1984 : : return f1->LoopVar() == f2->LoopVar() &&
1985 : : same_expr(f1->LoopExpr(), f2->LoopExpr()) &&
1986 [ # # ][ # # ]: 0 : same_stmt(f1->LoopBody(), f2->LoopBody());
[ # # ]
1987 : : }
1988 : :
1989 : : case STMT_IF:
1990 : : {
1991 : 0 : const IfStmt* i1 = (const IfStmt*) s1;
1992 : 0 : const IfStmt* i2 = (const IfStmt*) s2;
1993 : :
1994 [ # # ]: 0 : if ( ! same_expr(i1->StmtExpr(), i2->StmtExpr()) )
1995 : 0 : return 0;
1996 : :
1997 [ # # ][ # # ]: 0 : if ( i1->TrueBranch() || i2->TrueBranch() )
[ # # ]
1998 : : {
1999 [ # # ][ # # ]: 0 : if ( ! i1->TrueBranch() || ! i2->TrueBranch() )
[ # # ]
2000 : 0 : return 0;
2001 [ # # ]: 0 : if ( ! same_stmt(i1->TrueBranch(), i2->TrueBranch()) )
2002 : 0 : return 0;
2003 : : }
2004 : :
2005 [ # # ][ # # ]: 0 : if ( i1->FalseBranch() || i2->FalseBranch() )
[ # # ]
2006 : : {
2007 [ # # ][ # # ]: 0 : if ( ! i1->FalseBranch() || ! i2->FalseBranch() )
[ # # ]
2008 : 0 : return 0;
2009 [ # # ]: 0 : if ( ! same_stmt(i1->FalseBranch(), i2->FalseBranch()) )
2010 : 0 : return 0;
2011 : : }
2012 : :
2013 : 0 : return 1;
2014 : : }
2015 : :
2016 : : case STMT_SWITCH:
2017 : : {
2018 : 0 : const SwitchStmt* sw1 = (const SwitchStmt*) s1;
2019 : 0 : const SwitchStmt* sw2 = (const SwitchStmt*) s2;
2020 : :
2021 [ # # ]: 0 : if ( ! same_expr(sw1->StmtExpr(), sw2->StmtExpr()) )
2022 : 0 : return 0;
2023 : :
2024 : 0 : const case_list* c1 = sw1->Cases();
2025 : 0 : const case_list* c2 = sw1->Cases();
2026 : :
2027 [ # # ]: 0 : if ( c1->length() != c2->length() )
2028 : 0 : return 0;
2029 : :
2030 [ # # ]: 0 : loop_over_list(*c1, i)
2031 : : {
2032 [ # # ]: 0 : if ( ! same_expr((*c1)[i]->Cases(), (*c2)[i]->Cases()) )
2033 : 0 : return 0;
2034 [ # # ]: 0 : if ( ! same_stmt((*c1)[i]->Body(), (*c2)[i]->Body()) )
2035 : 0 : return 0;
2036 : : }
2037 : :
2038 : 0 : return 1;
2039 : : }
2040 : :
2041 : : case STMT_LIST:
2042 : : case STMT_EVENT_BODY_LIST:
2043 : : {
2044 : 0 : const stmt_list& l1 = ((const StmtList*) s1)->Stmts();
2045 : 0 : const stmt_list& l2 = ((const StmtList*) s2)->Stmts();
2046 : :
2047 [ # # ]: 0 : if ( l1.length() != l2.length() )
2048 : 0 : return 0;
2049 : :
2050 [ # # ]: 0 : loop_over_list(l1, i)
2051 [ # # ]: 0 : if ( ! same_stmt(l1[i], l2[i]) )
2052 : 0 : return 0;
2053 : :
2054 : 0 : return 1;
2055 : : }
2056 : :
2057 : : case STMT_INIT:
2058 : : {
2059 : 0 : const id_list* i1 = ((const InitStmt*) s1)->Inits();
2060 : 0 : const id_list* i2 = ((const InitStmt*) s2)->Inits();
2061 : :
2062 [ # # ]: 0 : if ( i1->length() != i2->length() )
2063 : 0 : return 0;
2064 : :
2065 [ # # ]: 0 : loop_over_list(*i1, i)
2066 [ # # ]: 0 : if ( (*i1)[i] != (*i2)[i] )
2067 : 0 : return 0;
2068 : :
2069 : 0 : return 1;
2070 : : }
2071 : :
2072 : : case STMT_WHEN:
2073 : : {
2074 : 0 : const WhenStmt* w1 = (const WhenStmt*) s1;
2075 : 0 : const WhenStmt* w2 = (const WhenStmt*) s2;
2076 : :
2077 [ # # ]: 0 : if ( ! same_expr(w1->Cond(), w2->Cond()) )
2078 : 0 : return 0;
2079 : :
2080 [ # # ]: 0 : if ( ! same_stmt(w1->Body(), w2->Body()) )
2081 : 0 : return 0;
2082 : :
2083 [ # # ][ # # ]: 0 : if ( w1->TimeoutBody() || w2->TimeoutBody() )
[ # # ]
2084 : : {
2085 [ # # ][ # # ]: 0 : if ( ! w1->TimeoutBody() || ! w2->TimeoutBody() )
[ # # ]
2086 : 0 : return 0;
2087 : :
2088 [ # # ]: 0 : if ( ! same_expr(w1->TimeoutExpr(), w2->TimeoutExpr()) )
2089 : 0 : return 0;
2090 : :
2091 [ # # ]: 0 : if ( ! same_stmt(w1->TimeoutBody(), w2->TimeoutBody()) )
2092 : 0 : return 0;
2093 : : }
2094 : :
2095 : 0 : return 1;
2096 : : }
2097 : :
2098 : : case STMT_NEXT:
2099 : : case STMT_BREAK:
2100 : : case STMT_NULL:
2101 : 0 : return 1;
2102 : :
2103 : : default:
2104 : 0 : error("bad tag in same_stmt()");
2105 : : }
2106 : :
2107 : 0 : return 0;
2108 [ + - ][ + - ]: 6 : }
|