source: src/ControlStruct/ExceptTranslate.cc@ 046a890

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast new-ast-unique-expr pthread-emulation qualifiedEnum stuck-waitfor-destruct
Last change on this file since 046a890 was 046a890, checked in by Andrew Beach <ajbeach@…>, 6 years ago

That should get default operations working for throws. More tests to come.

  • Property mode set to 100644
File size: 22.2 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// ExceptVisitor.cc --
8//
9// Author : Andrew Beach
10// Created On : Wed Jun 14 16:49:00 2017
11// Last Modified By : Andrew Beach
12// Last Modified On : Tue May 19 16:46:00 2020
13// Update Count : 14
14//
15
16#include "ExceptTranslate.h"
17
18#include <stddef.h> // for NULL
19#include <cassert> // for assert, assertf
20#include <iterator> // for back_inserter, inserter
21#include <string> // for string, operator==
22
23#include "Common/PassVisitor.h" // for PassVisitor, WithGuards
24#include "Common/SemanticError.h" // for SemanticError
25#include "Common/utility.h" // for CodeLocation
26#include "SynTree/LinkageSpec.h" // for Cforall
27#include "SynTree/Attribute.h" // for Attribute
28#include "SynTree/Constant.h" // for Constant
29#include "SynTree/Declaration.h" // for ObjectDecl, FunctionDecl, Struc...
30#include "SynTree/Expression.h" // for UntypedExpr, ConstantExpr, Name...
31#include "SynTree/Initializer.h" // for SingleInit, ListInit
32#include "SynTree/Label.h" // for Label
33#include "SynTree/Mutator.h" // for mutateAll
34#include "SynTree/Statement.h" // for CompoundStmt, CatchStmt, ThrowStmt
35#include "SynTree/Type.h" // for FunctionType, Type, noQualifiers
36#include "SynTree/DeclReplacer.h" // for DeclReplacer
37#include "SynTree/Visitor.h" // for acceptAll
38
39namespace ControlStruct {
40
41 // Buricratic Helpers (Not having to do with the paritular operation.)
42
43 typedef std::list<CatchStmt*> CatchList;
44
45 void split( CatchList& allHandlers, CatchList& terHandlers,
46 CatchList& resHandlers ) {
47 while ( !allHandlers.empty() ) {
48 CatchStmt * stmt = allHandlers.front();
49 allHandlers.pop_front();
50 if (CatchStmt::Terminate == stmt->get_kind()) {
51 terHandlers.push_back(stmt);
52 } else {
53 resHandlers.push_back(stmt);
54 }
55 }
56 }
57
58 void appendDeclStmt( CompoundStmt * block, Declaration * item ) {
59 block->push_back(new DeclStmt(item));
60 }
61
62 Expression * nameOf( DeclarationWithType * decl ) {
63 return new VariableExpr( decl );
64 }
65
66 class ThrowMutatorCore : public WithGuards {
67 ObjectDecl * terminate_handler_except;
68 enum Context { NoHandler, TerHandler, ResHandler } cur_context;
69
70 // The helper functions for code/syntree generation.
71 Statement * create_either_throw(
72 ThrowStmt * throwStmt, const char * throwFunc );
73 Statement * create_terminate_rethrow( ThrowStmt * throwStmt );
74 Statement * create_resume_rethrow( ThrowStmt * throwStmt );
75
76 public:
77 ThrowMutatorCore() :
78 terminate_handler_except( nullptr ),
79 cur_context( NoHandler )
80 {}
81
82 void premutate( CatchStmt *catchStmt );
83 Statement * postmutate( ThrowStmt *throwStmt );
84 };
85
86 // ThrowStmt Mutation Helpers
87
88 Statement * ThrowMutatorCore::create_either_throw(
89 ThrowStmt * throwStmt, const char * throwFunc ) {
90 // `throwFunc`( `throwStmt->get_name()` );
91 UntypedExpr * call = new UntypedExpr( new NameExpr( throwFunc ) );
92 call->get_args().push_back( throwStmt->get_expr() );
93 throwStmt->set_expr( nullptr );
94 delete throwStmt;
95 return new ExprStmt( call );
96 }
97
98 Statement * ThrowMutatorCore::create_terminate_rethrow(
99 ThrowStmt *throwStmt ) {
100 // { `terminate_handler_except` = 0p; __rethrow_terminate(); }
101 assert( nullptr == throwStmt->get_expr() );
102 assert( terminate_handler_except );
103
104 CompoundStmt * result = new CompoundStmt();
105 result->labels = throwStmt->labels;
106 result->push_back( new ExprStmt( UntypedExpr::createAssign(
107 nameOf( terminate_handler_except ),
108 new ConstantExpr( Constant::null(
109 //new PointerType(
110 // noQualifiers,
111 terminate_handler_except->get_type()->clone()
112 // )
113 ) )
114 ) ) );
115 result->push_back( new ExprStmt(
116 new UntypedExpr( new NameExpr( "__cfaehm_rethrow_terminate" ) )
117 ) );
118 delete throwStmt;
119 return result;
120 }
121
122 Statement * ThrowMutatorCore::create_resume_rethrow(
123 ThrowStmt *throwStmt ) {
124 // return false;
125 Statement * result = new ReturnStmt(
126 new ConstantExpr( Constant::from_bool( false ) )
127 );
128 result->labels = throwStmt->labels;
129 delete throwStmt;
130 return result;
131 }
132
133 // Visiting/Mutating Functions
134
135 void ThrowMutatorCore::premutate( CatchStmt *catchStmt ) {
136 // Validate the statement's form.
137 ObjectDecl * decl = dynamic_cast<ObjectDecl *>( catchStmt->get_decl() );
138 // Also checking the type would be nice.
139 if ( decl ) {
140 // Pass.
141 } else if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
142 SemanticError(catchStmt->location, "catch must have exception type");
143 } else {
144 SemanticError(catchStmt->location, "catchResume must have exception type");
145 }
146
147 // Track the handler context.
148 GuardValue( cur_context );
149 if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
150 cur_context = TerHandler;
151
152 GuardValue( terminate_handler_except );
153 terminate_handler_except = decl;
154 } else {
155 cur_context = ResHandler;
156 }
157 }
158
159 Statement * ThrowMutatorCore::postmutate( ThrowStmt *throwStmt ) {
160 // Ignoring throwStmt->get_target() for now.
161 if ( ThrowStmt::Terminate == throwStmt->get_kind() ) {
162 if ( throwStmt->get_expr() ) {
163 return create_either_throw( throwStmt, "$throw" );
164 } else if ( TerHandler == cur_context ) {
165 return create_terminate_rethrow( throwStmt );
166 } else {
167 abort("Invalid throw in %s at %i\n",
168 throwStmt->location.filename.c_str(),
169 throwStmt->location.first_line);
170 }
171 } else {
172 if ( throwStmt->get_expr() ) {
173 return create_either_throw( throwStmt, "$throwResume" );
174 } else if ( ResHandler == cur_context ) {
175 return create_resume_rethrow( throwStmt );
176 } else {
177 abort("Invalid throwResume in %s at %i\n",
178 throwStmt->location.filename.c_str(),
179 throwStmt->location.first_line);
180 }
181 }
182 }
183
184 class TryMutatorCore : public WithGuards {
185 enum Context { NoHandler, TerHandler, ResHandler };
186
187 // Also need to handle goto, break & continue.
188 // They need to be cut off in a ResHandler, until we enter another
189 // loop, switch or the goto stays within the function.
190
191 Context cur_context;
192
193 // The current (innermost) termination handler exception declaration.
194 ObjectDecl * handler_except_decl;
195
196 // The built in types used in translation.
197 StructDecl * except_decl;
198 StructDecl * node_decl;
199 StructDecl * hook_decl;
200
201 // The many helper functions for code/syntree generation.
202 CompoundStmt * take_try_block( TryStmt * tryStmt );
203 FunctionDecl * create_try_wrapper( CompoundStmt * body );
204 FunctionDecl * create_terminate_catch( CatchList &handlers );
205 CompoundStmt * create_single_matcher(
206 DeclarationWithType * except_obj, CatchStmt * modded_handler );
207 FunctionDecl * create_terminate_match( CatchList &handlers );
208 CompoundStmt * create_terminate_caller( FunctionDecl * try_wrapper,
209 FunctionDecl * terminate_catch, FunctionDecl * terminate_match );
210 FunctionDecl * create_resume_handler( CatchList &handlers );
211 CompoundStmt * create_resume_wrapper(
212 Statement * wraps, FunctionDecl * resume_handler );
213 FunctionDecl * create_finally_wrapper( TryStmt * tryStmt );
214 ObjectDecl * create_finally_hook( FunctionDecl * finally_wrapper );
215
216 // Types used in translation, make sure to use clone.
217 // void (*function)();
218 FunctionType try_func_t;
219 // void (*function)(int, exception);
220 FunctionType catch_func_t;
221 // int (*function)(exception);
222 FunctionType match_func_t;
223 // bool (*function)(exception);
224 FunctionType handle_func_t;
225 // void (*function)(__attribute__((unused)) void *);
226 FunctionType finally_func_t;
227
228 StructInstType * create_except_type() {
229 assert( except_decl );
230 return new StructInstType( noQualifiers, except_decl );
231 }
232 void init_func_types();
233
234 public:
235 TryMutatorCore() :
236 cur_context( NoHandler ),
237 handler_except_decl( nullptr ),
238 except_decl( nullptr ), node_decl( nullptr ), hook_decl( nullptr ),
239 try_func_t( noQualifiers, false ),
240 catch_func_t( noQualifiers, false ),
241 match_func_t( noQualifiers, false ),
242 handle_func_t( noQualifiers, false ),
243 finally_func_t( noQualifiers, false )
244 {}
245
246 void premutate( CatchStmt *catchStmt );
247 void premutate( StructDecl *structDecl );
248 Statement * postmutate( ThrowStmt *throwStmt );
249 Statement * postmutate( TryStmt *tryStmt );
250 };
251
252 void TryMutatorCore::init_func_types() {
253 assert( except_decl );
254
255 ObjectDecl index_obj(
256 "__handler_index",
257 Type::StorageClasses(),
258 LinkageSpec::Cforall,
259 /*bitfieldWidth*/ NULL,
260 new BasicType( noQualifiers, BasicType::SignedInt ),
261 /*init*/ NULL
262 );
263 ObjectDecl exception_obj(
264 "__exception_inst",
265 Type::StorageClasses(),
266 LinkageSpec::Cforall,
267 /*bitfieldWidth*/ NULL,
268 new PointerType(
269 noQualifiers,
270 new StructInstType( noQualifiers, except_decl )
271 ),
272 /*init*/ NULL
273 );
274 ObjectDecl bool_obj(
275 "__ret_bool",
276 Type::StorageClasses(),
277 LinkageSpec::Cforall,
278 /*bitfieldWidth*/ NULL,
279 new BasicType( noQualifiers, BasicType::Bool ),
280 /*init*/ NULL,
281 std::list<Attribute *>{ new Attribute( "unused" ) }
282 );
283 ObjectDecl voidptr_obj(
284 "__hook",
285 Type::StorageClasses(),
286 LinkageSpec::Cforall,
287 NULL,
288 new PointerType(
289 noQualifiers,
290 new VoidType(
291 noQualifiers
292 ),
293 std::list<Attribute *>{ new Attribute( "unused" ) }
294 ),
295 NULL
296 );
297
298 ObjectDecl * unused_index_obj = index_obj.clone();
299 unused_index_obj->attributes.push_back( new Attribute( "unused" ) );
300
301 catch_func_t.get_parameters().push_back( index_obj.clone() );
302 catch_func_t.get_parameters().push_back( exception_obj.clone() );
303 match_func_t.get_returnVals().push_back( unused_index_obj );
304 match_func_t.get_parameters().push_back( exception_obj.clone() );
305 handle_func_t.get_returnVals().push_back( bool_obj.clone() );
306 handle_func_t.get_parameters().push_back( exception_obj.clone() );
307 finally_func_t.get_parameters().push_back( voidptr_obj.clone() );
308 }
309
310 // TryStmt Mutation Helpers
311
312 CompoundStmt * TryMutatorCore::take_try_block( TryStmt *tryStmt ) {
313 CompoundStmt * block = tryStmt->get_block();
314 tryStmt->set_block( nullptr );
315 return block;
316 }
317
318 FunctionDecl * TryMutatorCore::create_try_wrapper(
319 CompoundStmt *body ) {
320
321 return new FunctionDecl( "try", Type::StorageClasses(),
322 LinkageSpec::Cforall, try_func_t.clone(), body );
323 }
324
325 FunctionDecl * TryMutatorCore::create_terminate_catch(
326 CatchList &handlers ) {
327 std::list<CaseStmt *> handler_wrappers;
328
329 FunctionType *func_type = catch_func_t.clone();
330 DeclarationWithType * index_obj = func_type->get_parameters().front();
331 DeclarationWithType * except_obj = func_type->get_parameters().back();
332
333 // Index 1..{number of handlers}
334 int index = 0;
335 CatchList::iterator it = handlers.begin();
336 for ( ; it != handlers.end() ; ++it ) {
337 ++index;
338 CatchStmt * handler = *it;
339
340 // case `index`:
341 // {
342 // `handler.decl` = { (virtual `decl.type`)`except` };
343 // `handler.body`;
344 // }
345 // return;
346 CompoundStmt * block = new CompoundStmt();
347
348 // Just copy the exception value. (Post Validation)
349 ObjectDecl * handler_decl =
350 static_cast<ObjectDecl *>( handler->get_decl() );
351 ObjectDecl * local_except = handler_decl->clone();
352 local_except->set_init(
353 new ListInit({ new SingleInit(
354 new VirtualCastExpr( nameOf( except_obj ),
355 local_except->get_type()
356 )
357 ) })
358 );
359 block->push_back( new DeclStmt( local_except ) );
360
361 // Add the cleanup attribute.
362 local_except->get_attributes().push_back( new Attribute(
363 "cleanup",
364 { new NameExpr( "__cfaehm_cleanup_terminate" ) }
365 ) );
366
367 // Update variables in the body to point to this local copy.
368 {
369 DeclReplacer::DeclMap mapping;
370 mapping[ handler_decl ] = local_except;
371 DeclReplacer::replace( handler->body, mapping );
372 }
373
374 block->push_back( handler->body );
375 handler->body = nullptr;
376
377 std::list<Statement *> caseBody
378 { block, new ReturnStmt( nullptr ) };
379 handler_wrappers.push_back( new CaseStmt(
380 new ConstantExpr( Constant::from_int( index ) ),
381 caseBody
382 ) );
383 }
384 // TODO: Some sort of meaningful error on default perhaps?
385
386 std::list<Statement*> stmt_handlers;
387 while ( !handler_wrappers.empty() ) {
388 stmt_handlers.push_back( handler_wrappers.front() );
389 handler_wrappers.pop_front();
390 }
391
392 SwitchStmt * handler_lookup = new SwitchStmt(
393 nameOf( index_obj ),
394 stmt_handlers
395 );
396 CompoundStmt * body = new CompoundStmt();
397 body->push_back( handler_lookup );
398
399 return new FunctionDecl("catch", Type::StorageClasses(),
400 LinkageSpec::Cforall, func_type, body);
401 }
402
403 // Create a single check from a moddified handler.
404 // except_obj is referenced, modded_handler will be freed.
405 CompoundStmt * TryMutatorCore::create_single_matcher(
406 DeclarationWithType * except_obj, CatchStmt * modded_handler ) {
407 // {
408 // `modded_handler.decl`
409 // if ( `decl.name = (virtual `decl.type`)`except`
410 // [&& `modded_handler.cond`] ) {
411 // `modded_handler.body`
412 // }
413 // }
414
415 CompoundStmt * block = new CompoundStmt();
416
417 // Local Declaration
418 ObjectDecl * local_except =
419 dynamic_cast<ObjectDecl *>( modded_handler->get_decl() );
420 assert( local_except );
421 block->push_back( new DeclStmt( local_except ) );
422
423 // Check for type match.
424 Expression * cond = UntypedExpr::createAssign( nameOf( local_except ),
425 new VirtualCastExpr( nameOf( except_obj ),
426 local_except->get_type()->clone() ) );
427
428 // Add the check on the conditional if it is provided.
429 if ( modded_handler->get_cond() ) {
430 cond = new LogicalExpr( cond, modded_handler->get_cond() );
431 }
432 // Construct the match condition.
433 block->push_back( new IfStmt(
434 cond, modded_handler->get_body(), nullptr ) );
435
436 modded_handler->set_decl( nullptr );
437 modded_handler->set_cond( nullptr );
438 modded_handler->set_body( nullptr );
439 delete modded_handler;
440 return block;
441 }
442
443 FunctionDecl * TryMutatorCore::create_terminate_match(
444 CatchList &handlers ) {
445 // int match(exception * except) {
446 // HANDLER WRAPPERS { return `index`; }
447 // }
448
449 CompoundStmt * body = new CompoundStmt();
450
451 FunctionType * func_type = match_func_t.clone();
452 DeclarationWithType * except_obj = func_type->get_parameters().back();
453
454 // Index 1..{number of handlers}
455 int index = 0;
456 CatchList::iterator it;
457 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
458 ++index;
459 CatchStmt * handler = *it;
460
461 // Body should have been taken by create_terminate_catch.
462 assert( nullptr == handler->get_body() );
463
464 // Create new body.
465 handler->set_body( new ReturnStmt(
466 new ConstantExpr( Constant::from_int( index ) ) ) );
467
468 // Create the handler.
469 body->push_back( create_single_matcher( except_obj, handler ) );
470 *it = nullptr;
471 }
472
473 body->push_back( new ReturnStmt(
474 new ConstantExpr( Constant::from_int( 0 ) ) ) );
475
476 return new FunctionDecl("match", Type::StorageClasses(),
477 LinkageSpec::Cforall, func_type, body);
478 }
479
480 CompoundStmt * TryMutatorCore::create_terminate_caller(
481 FunctionDecl * try_wrapper,
482 FunctionDecl * terminate_catch,
483 FunctionDecl * terminate_match ) {
484 // { __cfaehm_try_terminate(`try`, `catch`, `match`); }
485
486 UntypedExpr * caller = new UntypedExpr( new NameExpr(
487 "__cfaehm_try_terminate" ) );
488 std::list<Expression *>& args = caller->get_args();
489 args.push_back( nameOf( try_wrapper ) );
490 args.push_back( nameOf( terminate_catch ) );
491 args.push_back( nameOf( terminate_match ) );
492
493 CompoundStmt * callStmt = new CompoundStmt();
494 callStmt->push_back( new ExprStmt( caller ) );
495 return callStmt;
496 }
497
498 FunctionDecl * TryMutatorCore::create_resume_handler(
499 CatchList &handlers ) {
500 // bool handle(exception * except) {
501 // HANDLER WRAPPERS { `hander->body`; return true; }
502 // }
503 CompoundStmt * body = new CompoundStmt();
504
505 FunctionType * func_type = handle_func_t.clone();
506 DeclarationWithType * except_obj = func_type->get_parameters().back();
507
508 CatchList::iterator it;
509 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
510 CatchStmt * handler = *it;
511
512 // Modifiy body.
513 CompoundStmt * handling_code =
514 dynamic_cast<CompoundStmt*>( handler->get_body() );
515 if ( ! handling_code ) {
516 handling_code = new CompoundStmt();
517 handling_code->push_back( handler->get_body() );
518 }
519 handling_code->push_back( new ReturnStmt(
520 new ConstantExpr( Constant::from_bool( true ) ) ) );
521 handler->set_body( handling_code );
522
523 // Create the handler.
524 body->push_back( create_single_matcher( except_obj, handler ) );
525 *it = nullptr;
526 }
527
528 body->push_back( new ReturnStmt(
529 new ConstantExpr( Constant::from_bool( false ) ) ) );
530
531 return new FunctionDecl("handle", Type::StorageClasses(),
532 LinkageSpec::Cforall, func_type, body);
533 }
534
535 CompoundStmt * TryMutatorCore::create_resume_wrapper(
536 Statement * wraps,
537 FunctionDecl * resume_handler ) {
538 CompoundStmt * body = new CompoundStmt();
539
540 // struct __try_resume_node __resume_node
541 // __attribute__((cleanup( __cfaehm_try_resume_cleanup )));
542 // ** unwinding of the stack here could cause problems **
543 // ** however I don't think that can happen currently **
544 // __cfaehm_try_resume_setup( &__resume_node, resume_handler );
545
546 std::list< Attribute * > attributes;
547 {
548 std::list< Expression * > attr_params;
549 attr_params.push_back( new NameExpr(
550 "__cfaehm_try_resume_cleanup" ) );
551 attributes.push_back( new Attribute( "cleanup", attr_params ) );
552 }
553
554 ObjectDecl * obj = new ObjectDecl(
555 "__resume_node",
556 Type::StorageClasses(),
557 LinkageSpec::Cforall,
558 nullptr,
559 new StructInstType(
560 Type::Qualifiers(),
561 node_decl
562 ),
563 nullptr,
564 attributes
565 );
566 appendDeclStmt( body, obj );
567
568 UntypedExpr *setup = new UntypedExpr( new NameExpr(
569 "__cfaehm_try_resume_setup" ) );
570 setup->get_args().push_back( new AddressExpr( nameOf( obj ) ) );
571 setup->get_args().push_back( nameOf( resume_handler ) );
572
573 body->push_back( new ExprStmt( setup ) );
574
575 body->push_back( wraps );
576 return body;
577 }
578
579 FunctionDecl * TryMutatorCore::create_finally_wrapper(
580 TryStmt * tryStmt ) {
581 // void finally() { <finally code> }
582 FinallyStmt * finally = tryStmt->get_finally();
583 CompoundStmt * body = finally->get_block();
584 finally->set_block( nullptr );
585 delete finally;
586 tryStmt->set_finally( nullptr );
587
588 return new FunctionDecl("finally", Type::StorageClasses(),
589 LinkageSpec::Cforall, finally_func_t.clone(), body);
590 }
591
592 ObjectDecl * TryMutatorCore::create_finally_hook(
593 FunctionDecl * finally_wrapper ) {
594 // struct __cfaehm_cleanup_hook __finally_hook
595 // __attribute__((cleanup( `finally_wrapper` )));
596
597 // Make Cleanup Attribute.
598 std::list< Attribute * > attributes;
599 {
600 std::list< Expression * > attr_params;
601 attr_params.push_back( nameOf( finally_wrapper ) );
602 attributes.push_back( new Attribute( "cleanup", attr_params ) );
603 }
604
605 return new ObjectDecl(
606 "__finally_hook",
607 Type::StorageClasses(),
608 LinkageSpec::Cforall,
609 nullptr,
610 new StructInstType(
611 noQualifiers,
612 hook_decl
613 ),
614 nullptr,
615 attributes
616 );
617 }
618
619 // Visiting/Mutating Functions
620 void TryMutatorCore::premutate( CatchStmt *catchStmt ) {
621 // Validate the Statement's form.
622 ObjectDecl * decl = dynamic_cast<ObjectDecl *>( catchStmt->get_decl() );
623 if ( decl && true /* check decl->get_type() */ ) {
624 // Pass.
625 } else if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
626 SemanticError(catchStmt->location, "catch must have exception type");
627 } else {
628 SemanticError(catchStmt->location, "catchResume must have exception type");
629 }
630
631 // Track the handler context.
632 GuardValue( cur_context );
633 if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
634 cur_context = TerHandler;
635
636 GuardValue( handler_except_decl );
637 handler_except_decl = decl;
638 } else {
639 cur_context = ResHandler;
640 }
641 }
642
643 void TryMutatorCore::premutate( StructDecl *structDecl ) {
644 if ( !structDecl->has_body() ) {
645 // Skip children?
646 return;
647 } else if ( structDecl->get_name() == "__cfaehm_base_exception_t" ) {
648 assert( nullptr == except_decl );
649 except_decl = structDecl;
650 init_func_types();
651 } else if ( structDecl->get_name() == "__cfaehm_try_resume_node" ) {
652 assert( nullptr == node_decl );
653 node_decl = structDecl;
654 } else if ( structDecl->get_name() == "__cfaehm_cleanup_hook" ) {
655 assert( nullptr == hook_decl );
656 hook_decl = structDecl;
657 }
658 }
659
660 Statement * TryMutatorCore::postmutate( ThrowStmt * ) {
661 // All throws should be removed by this point.
662 assert( false );
663 }
664
665 Statement * TryMutatorCore::postmutate( TryStmt *tryStmt ) {
666 assert( except_decl );
667 assert( node_decl );
668 assert( hook_decl );
669
670 // Generate a prefix for the function names?
671
672 CompoundStmt * block = new CompoundStmt();
673 CompoundStmt * inner = take_try_block( tryStmt );
674
675 if ( tryStmt->get_finally() ) {
676 // Define the helper function.
677 FunctionDecl * finally_block =
678 create_finally_wrapper( tryStmt );
679 appendDeclStmt( block, finally_block );
680 // Create and add the finally cleanup hook.
681 appendDeclStmt( block, create_finally_hook( finally_block ) );
682 }
683
684 CatchList termination_handlers;
685 CatchList resumption_handlers;
686 split( tryStmt->get_catchers(),
687 termination_handlers, resumption_handlers );
688
689 if ( resumption_handlers.size() ) {
690 // Define the helper function.
691 FunctionDecl * resume_handler =
692 create_resume_handler( resumption_handlers );
693 appendDeclStmt( block, resume_handler );
694 // Prepare hooks
695 inner = create_resume_wrapper( inner, resume_handler );
696 }
697
698 if ( termination_handlers.size() ) {
699 // Define the three helper functions.
700 FunctionDecl * try_wrapper = create_try_wrapper( inner );
701 appendDeclStmt( block, try_wrapper );
702 FunctionDecl * terminate_catch =
703 create_terminate_catch( termination_handlers );
704 appendDeclStmt( block, terminate_catch );
705 FunctionDecl * terminate_match =
706 create_terminate_match( termination_handlers );
707 appendDeclStmt( block, terminate_match );
708 // Build the call to the try wrapper.
709 inner = create_terminate_caller(
710 try_wrapper, terminate_catch, terminate_match );
711 }
712
713 // Embed the try block.
714 block->push_back( inner );
715
716 return block;
717 }
718
719 void translateThrows( std::list< Declaration *> & translationUnit ) {
720 PassVisitor<ThrowMutatorCore> translator;
721 mutateAll( translationUnit, translator );
722 }
723
724 void translateTries( std::list< Declaration *> & translationUnit ) {
725 PassVisitor<TryMutatorCore> translator;
726 mutateAll( translationUnit, translator );
727 }
728}
Note: See TracBrowser for help on using the repository browser.