source: src/ControlStruct/ExceptTranslateNew.cpp@ 0d0931d

ADT ast-experimental
Last change on this file since 0d0931d was c36814a, checked in by Andrew Beach <ajbeach@…>, 3 years ago

Adding 'final' and removing a redundent namespace in the post resolve new ast code.

  • Property mode set to 100644
File size: 22.0 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// ExceptTranslateNew.cpp -- Conversion of exception control flow structures.
8//
9// Author : Andrew Beach
10// Created On : Mon Nov 8 11:53:00 2021
11// Last Modified By : Andrew Beach
12// Last Modified On : Fri Mar 11 17:51:00 2022
13// Update Count : 2
14//
15
16#include "ExceptTranslate.h"
17
18#include "AST/Expr.hpp"
19#include "AST/Pass.hpp"
20#include "AST/Stmt.hpp"
21#include "AST/TranslationUnit.hpp"
22#include "AST/DeclReplacer.hpp"
23
24namespace ControlStruct {
25
26namespace {
27
28 typedef std::list<ast::CatchClause*> CatchList;
29
30 void appendDeclStmt( ast::CompoundStmt * block, ast::DeclWithType * item ) {
31 block->push_back(new ast::DeclStmt(block->location, item));
32 }
33
34class TranslateThrowsCore final : public ast::WithGuards {
35 const ast::ObjectDecl * terminateHandlerExcept;
36 enum Context { NoHandler, TerHandler, ResHandler } currentContext;
37
38 const ast::Stmt * createEitherThrow(
39 const ast::ThrowStmt * throwStmt, const char * funcName );
40 const ast::Stmt * createTerminateRethrow( const ast::ThrowStmt * );
41
42public:
43 TranslateThrowsCore() :
44 terminateHandlerExcept( nullptr ), currentContext( NoHandler )
45 {}
46
47 void previsit( const ast::CatchClause * stmt );
48 const ast::Stmt * postvisit( const ast::ThrowStmt * stmt );
49};
50
51const ast::Stmt * TranslateThrowsCore::createEitherThrow(
52 const ast::ThrowStmt * throwStmt, const char * funcName ) {
53 // `throwFunc`( `throwStmt->name` );
54 ast::UntypedExpr * call = new ast::UntypedExpr( throwStmt->location,
55 new ast::NameExpr( throwStmt->location, funcName )
56 );
57 call->args.push_back( throwStmt->expr );
58 return new ast::ExprStmt( throwStmt->location, call );
59}
60
61ast::VariableExpr * varOf( const ast::DeclWithType * decl ) {
62 return new ast::VariableExpr( decl->location, decl );
63}
64
65const ast::Stmt * TranslateThrowsCore::createTerminateRethrow(
66 const ast::ThrowStmt * stmt ) {
67 // { `terminate_handler_except` = 0p; __rethrow_terminate(); }
68 assert( nullptr == stmt->expr );
69 assert( terminateHandlerExcept );
70
71 ast::CompoundStmt * result = new ast::CompoundStmt(
72 stmt->location, {}, std::vector<ast::Label>( stmt->labels ) );
73 result->push_back( new ast::ExprStmt( stmt->location,
74 ast::UntypedExpr::createAssign(
75 stmt->location,
76 varOf( terminateHandlerExcept ),
77 ast::ConstantExpr::null(
78 stmt->location,
79 terminateHandlerExcept->type
80 )
81 )
82 ) );
83 result->push_back( new ast::ExprStmt( stmt->location, new ast::UntypedExpr(
84 stmt->location,
85 new ast::NameExpr( stmt->location, "__cfaehm_rethrow_terminate" )
86 ) ) );
87 return result;
88}
89
90void TranslateThrowsCore::previsit( const ast::CatchClause * stmt ) {
91 // Validate the statement's form.
92 const ast::ObjectDecl * decl = stmt->decl.as<ast::ObjectDecl>();
93 // Also checking the type would be nice.
94 if ( !decl || !decl->type.as<ast::PointerType>() ) {
95 std::string kind = (ast::Terminate == stmt->kind) ? "catch" : "catchResume";
96 SemanticError( stmt->location, kind + " must have pointer to an exception type" );
97 }
98
99 // Track the handler context.
100 if ( ast::Terminate == stmt->kind ) {
101 GuardValue( currentContext ) = TerHandler;
102 GuardValue( terminateHandlerExcept ) = decl;
103 } else {
104 GuardValue( currentContext ) = ResHandler;
105 }
106}
107
108const ast::Stmt * TranslateThrowsCore::postvisit(
109 const ast::ThrowStmt * stmt ) {
110 // Ignoring ThrowStmt::target for now.
111 // Handle Termination (Raise, Reraise, Error):
112 if ( ast::Terminate == stmt->kind ) {
113 if ( stmt->expr ) {
114 return createEitherThrow( stmt, "$throw" );
115 } else if ( TerHandler == currentContext ) {
116 return createTerminateRethrow( stmt );
117 } else {
118 abort( "Invalid throw in %s at %i\n",
119 stmt->location.filename.c_str(),
120 stmt->location.first_line);
121 }
122 // Handle Resumption (Raise, Reraise, Error):
123 } else {
124 if ( stmt->expr ) {
125 return createEitherThrow( stmt, "$throwResume" );
126 } else if ( ResHandler == currentContext ) {
127 // This has to be handled later.
128 return stmt;
129 } else {
130 abort( "Invalid throwResume in %s at %i\n",
131 stmt->location.filename.c_str(),
132 stmt->location.first_line);
133 }
134 }
135}
136
137
138class TryMutatorCore final {
139 // The built in types used in translation.
140 const ast::StructDecl * except_decl;
141 const ast::StructDecl * node_decl;
142 const ast::StructDecl * hook_decl;
143
144 // The many helper functions for code/syntree generation.
145 ast::CompoundStmt * take_try_block( ast::TryStmt * tryStmt );
146 ast::FunctionDecl * create_try_wrapper( const ast::CompoundStmt * body );
147 ast::FunctionDecl * create_terminate_catch( CatchList &handlers );
148 ast::CompoundStmt * create_single_matcher(
149 const ast::DeclWithType * except_obj, ast::CatchClause * modded_handler );
150 ast::FunctionDecl * create_terminate_match( CatchList &handlers );
151 ast::CompoundStmt * create_terminate_caller( CodeLocation loc, ast::FunctionDecl * try_wrapper,
152 ast::FunctionDecl * terminate_catch, ast::FunctionDecl * terminate_match );
153 ast::FunctionDecl * create_resume_handler( CatchList &handlers );
154 ast::CompoundStmt * create_resume_wrapper(
155 const ast::Stmt * wraps, const ast::FunctionDecl * resume_handler );
156 ast::FunctionDecl * create_finally_wrapper( ast::TryStmt * tryStmt );
157 ast::ObjectDecl * create_finally_hook( ast::FunctionDecl * finally_wrapper );
158 ast::Stmt * create_resume_rethrow( const ast::ThrowStmt * throwStmt );
159
160 // Types used in translation, first group are internal.
161 ast::ObjectDecl * make_index_object( CodeLocation const & ) const;
162 ast::ObjectDecl * make_exception_object( CodeLocation const & ) const;
163 ast::ObjectDecl * make_bool_object( CodeLocation const & ) const;
164 ast::ObjectDecl * make_voidptr_object( CodeLocation const & ) const;
165 ast::ObjectDecl * make_unused_index_object( CodeLocation const & ) const;
166 // void (*function)();
167 ast::FunctionDecl * make_try_function( CodeLocation const & ) const;
168 // void (*function)(int, exception);
169 ast::FunctionDecl * make_catch_function( CodeLocation const & ) const;
170 // int (*function)(exception);
171 ast::FunctionDecl * make_match_function( CodeLocation const & ) const;
172 // bool (*function)(exception);
173 ast::FunctionDecl * make_handle_function( CodeLocation const & ) const;
174 // void (*function)(__attribute__((unused)) void *);
175 ast::FunctionDecl * make_finally_function( CodeLocation const & ) const;
176
177public:
178 TryMutatorCore() :
179 except_decl( nullptr ), node_decl( nullptr ), hook_decl( nullptr )
180 {}
181
182 void previsit( const ast::StructDecl *structDecl );
183 ast::Stmt * postvisit( const ast::TryStmt *tryStmt );
184 ast::Stmt * postvisit( const ast::ThrowStmt *throwStmt );
185};
186
187ast::ObjectDecl * TryMutatorCore::make_index_object(
188 CodeLocation const & location ) const {
189 return new ast::ObjectDecl(
190 location,
191 "__handler_index",
192 new ast::BasicType( ast::BasicType::SignedInt )
193 );
194}
195
196ast::ObjectDecl * TryMutatorCore::make_exception_object(
197 CodeLocation const & location ) const {
198 assert( except_decl );
199 return new ast::ObjectDecl(
200 location,
201 "__exception_inst",
202 new ast::PointerType( new ast::StructInstType( except_decl ) )
203 );
204}
205
206ast::ObjectDecl * TryMutatorCore::make_bool_object(
207 CodeLocation const & location ) const {
208 return new ast::ObjectDecl(
209 location,
210 "__ret_bool",
211 new ast::BasicType( ast::BasicType::Bool ),
212 nullptr, //init
213 ast::Storage::Classes{},
214 ast::Linkage::Cforall,
215 nullptr, //width
216 std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
217 );
218}
219
220ast::ObjectDecl * TryMutatorCore::make_voidptr_object(
221 CodeLocation const & location ) const {
222 return new ast::ObjectDecl(
223 location,
224 "__hook",
225 new ast::PointerType(
226 new ast::VoidType()
227 ),
228 nullptr, //init
229 ast::Storage::Classes{},
230 ast::Linkage::Cforall,
231 nullptr, //width
232 std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
233 );
234}
235
236ast::ObjectDecl * TryMutatorCore::make_unused_index_object(
237 CodeLocation const & location ) const {
238 return new ast::ObjectDecl(
239 location,
240 "__handler_index",
241 new ast::BasicType(ast::BasicType::SignedInt),
242 nullptr,
243 ast::Storage::Classes{},
244 ast::Linkage::Cforall,
245 nullptr, //width
246 std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
247 );
248}
249
250ast::FunctionDecl * TryMutatorCore::make_try_function(
251 CodeLocation const & location ) const {
252 return new ast::FunctionDecl(
253 location,
254 "try",
255 {}, //forall
256 {}, //no param
257 {}, //no return
258 nullptr,
259 ast::Storage::Classes{},
260 ast::Linkage::Cforall
261 );
262}
263
264ast::FunctionDecl * TryMutatorCore::make_catch_function(
265 CodeLocation const & location ) const {
266 return new ast::FunctionDecl(
267 location,
268 "catch",
269 {}, //forall
270 { make_index_object( location ), make_exception_object( location ) },
271 {}, //return void
272 nullptr,
273 ast::Storage::Classes{},
274 ast::Linkage::Cforall
275 );
276}
277
278ast::FunctionDecl * TryMutatorCore::make_match_function(
279 CodeLocation const & location ) const {
280 return new ast::FunctionDecl(
281 location,
282 "match",
283 {}, //forall
284 { make_exception_object( location ) },
285 { make_unused_index_object( location ) },
286 nullptr,
287 ast::Storage::Classes{},
288 ast::Linkage::Cforall
289 );
290}
291
292ast::FunctionDecl * TryMutatorCore::make_handle_function(
293 CodeLocation const & location ) const {
294 return new ast::FunctionDecl(
295 location,
296 "handle",
297 {}, //forall
298 { make_exception_object( location ) },
299 { make_bool_object( location ) },
300 nullptr,
301 ast::Storage::Classes{},
302 ast::Linkage::Cforall
303 );
304}
305
306ast::FunctionDecl * TryMutatorCore::make_finally_function(
307 CodeLocation const & location ) const {
308 return new ast::FunctionDecl(
309 location,
310 "finally",
311 {}, //forall
312 { make_voidptr_object( location ) },
313 {}, //return void
314 nullptr,
315 ast::Storage::Classes{},
316 ast::Linkage::Cforall
317 );
318}
319
320// TryStmt Mutation Helpers
321
322ast::FunctionDecl * TryMutatorCore::create_try_wrapper(
323 const ast::CompoundStmt *body ) {
324
325 ast::FunctionDecl * ret = make_try_function( body->location );
326 ret->stmts = body;
327 return ret;
328}
329
330ast::FunctionDecl * TryMutatorCore::create_terminate_catch(
331 CatchList &handlers ) {
332 std::vector<ast::ptr<ast::CaseClause>> handler_wrappers;
333
334 assert (!handlers.empty());
335 const CodeLocation loc = handlers.front()->location;
336
337 ast::FunctionDecl * func_t = make_catch_function( loc );
338 const ast::DeclWithType * index_obj = func_t->params.front();
339 const ast::DeclWithType * except_obj = func_t->params.back();
340
341 // Index 1..{number of handlers}
342 int index = 0;
343 CatchList::iterator it = handlers.begin();
344 for ( ; it != handlers.end() ; ++it ) {
345 ++index;
346 ast::CatchClause * handler = *it;
347 const CodeLocation loc = handler->location;
348
349 // case `index`:
350 // {
351 // `handler.decl` = { (virtual `decl.type`)`except` };
352 // `handler.body`;
353 // }
354 // return;
355 ast::CompoundStmt * block = new ast::CompoundStmt(loc);
356
357 // Just copy the exception value. (Post Validation)
358 const ast::ObjectDecl * handler_decl =
359 handler->decl.strict_as<ast::ObjectDecl>();
360 ast::ObjectDecl * local_except = ast::deepCopy(handler_decl);
361 ast::VirtualCastExpr * vcex = new ast::VirtualCastExpr(loc,
362 new ast::VariableExpr( loc, except_obj ),
363 local_except->get_type()
364 );
365 vcex->location = handler->location;
366 local_except->init = new ast::ListInit(loc, { new ast::SingleInit( loc, vcex ) });
367 block->push_back( new ast::DeclStmt( loc, local_except ) );
368
369 // Add the cleanup attribute.
370 local_except->attributes.push_back( new ast::Attribute(
371 "cleanup",
372 { new ast::NameExpr( loc, "__cfaehm_cleanup_terminate" ) }
373 ) );
374
375 ast::DeclReplacer::DeclMap mapping;
376 mapping[handler_decl] = local_except;
377 const ast::Stmt * mutBody = strict_dynamic_cast<const ast::Stmt *>(
378 ast::DeclReplacer::replace(handler->body, mapping));
379
380
381 block->push_back( mutBody );
382 // handler->body = nullptr;
383
384 handler_wrappers.push_back( new ast::CaseClause(loc,
385 ast::ConstantExpr::from_int(loc, index) ,
386 { block, new ast::ReturnStmt( loc, nullptr ) }
387 ));
388 }
389 // TODO: Some sort of meaningful error on default perhaps?
390
391 ast::SwitchStmt * handler_lookup = new ast::SwitchStmt( loc,
392 new ast::VariableExpr( loc, index_obj ),
393 std::move(handler_wrappers)
394 );
395 ast::CompoundStmt * body = new ast::CompoundStmt( loc, {handler_lookup} );
396
397 func_t->stmts = body;
398 return func_t;
399}
400
401// Create a single check from a moddified handler.
402// except_obj is referenced, modded_handler will be freed.
403ast::CompoundStmt * TryMutatorCore::create_single_matcher(
404 const ast::DeclWithType * except_obj, ast::CatchClause * modded_handler ) {
405 // {
406 // `modded_handler.decl`
407 // if ( `decl.name = (virtual `decl.type`)`except`
408 // [&& `modded_handler.cond`] ) {
409 // `modded_handler.body`
410 // }
411 // }
412
413 const CodeLocation loc = modded_handler->location;
414 ast::CompoundStmt * block = new ast::CompoundStmt(loc);
415
416 // Local Declaration
417 const ast::ObjectDecl * local_except =
418 modded_handler->decl.strict_as<ast::ObjectDecl>();
419 block->push_back( new ast::DeclStmt( loc, local_except ) );
420
421 // Check for type match.
422 ast::VirtualCastExpr * vcex = new ast::VirtualCastExpr(loc,
423 new ast::VariableExpr(loc, except_obj ),
424 local_except->get_type()
425 );
426 ast::Expr * cond = ast::UntypedExpr::createAssign(loc,
427 new ast::VariableExpr(loc, local_except ), vcex );
428
429 // Add the check on the conditional if it is provided.
430 if ( modded_handler->cond ) {
431 cond = new ast::LogicalExpr( loc, cond, modded_handler->cond, ast::LogicalFlag::AndExpr );
432 }
433 // Construct the match condition.
434 block->push_back( new ast::IfStmt(loc,
435 cond, modded_handler->body, nullptr ) );
436
437 return block;
438}
439
440ast::FunctionDecl * TryMutatorCore::create_terminate_match(
441 CatchList &handlers ) {
442 // int match(exception * except) {
443 // HANDLER WRAPPERS { return `index`; }
444 // }
445
446 assert (!handlers.empty());
447 const CodeLocation loc = handlers.front()->location;
448
449 ast::CompoundStmt * body = new ast::CompoundStmt(loc);
450
451 ast::FunctionDecl * func_t = make_match_function( loc );
452 const ast::DeclWithType * except_obj = func_t->params.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 ast::CatchClause * handler = *it;
460
461 // Body should have been taken by create_terminate_catch.
462 // xxx - just ignore it?
463 // assert( nullptr == handler->get_body() );
464
465 // Create new body.
466 handler->body = new ast::ReturnStmt( handler->location,
467 ast::ConstantExpr::from_int( handler->location, index ) );
468
469 // Create the handler.
470 body->push_back( create_single_matcher( except_obj, handler ) );
471 *it = nullptr;
472 }
473
474 body->push_back( new ast::ReturnStmt(loc,
475 ast::ConstantExpr::from_int( loc, 0 ) ));
476
477 func_t->stmts = body;
478
479 return func_t;
480}
481
482ast::CompoundStmt * TryMutatorCore::create_terminate_caller(
483 CodeLocation loc,
484 ast::FunctionDecl * try_wrapper,
485 ast::FunctionDecl * terminate_catch,
486 ast::FunctionDecl * terminate_match ) {
487 // { __cfaehm_try_terminate(`try`, `catch`, `match`); }
488
489 ast::UntypedExpr * caller = new ast::UntypedExpr(loc, new ast::NameExpr(loc,
490 "__cfaehm_try_terminate" ) );
491 caller->args.push_back( new ast::VariableExpr(loc, try_wrapper ) );
492 caller->args.push_back( new ast::VariableExpr(loc, terminate_catch ) );
493 caller->args.push_back( new ast::VariableExpr(loc, terminate_match ) );
494
495 ast::CompoundStmt * callStmt = new ast::CompoundStmt(loc);
496 callStmt->push_back( new ast::ExprStmt( loc, caller ) );
497 return callStmt;
498}
499
500ast::FunctionDecl * TryMutatorCore::create_resume_handler(
501 CatchList &handlers ) {
502 // bool handle(exception * except) {
503 // HANDLER WRAPPERS { `hander->body`; return true; }
504 // }
505 assert (!handlers.empty());
506 const CodeLocation loc = handlers.front()->location;
507 ast::CompoundStmt * body = new ast::CompoundStmt(loc);
508
509 ast::FunctionDecl * func_t = make_handle_function( loc );
510 const ast::DeclWithType * except_obj = func_t->params.back();
511
512 CatchList::iterator it;
513 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
514 ast::CatchClause * handler = *it;
515 const CodeLocation loc = handler->location;
516 // Modifiy body.
517 ast::CompoundStmt * handling_code;
518 if (handler->body.as<ast::CompoundStmt>()) {
519 handling_code = strict_dynamic_cast<ast::CompoundStmt*>(
520 handler->body.get_and_mutate() );
521 } else {
522 handling_code = new ast::CompoundStmt(loc);
523 handling_code->push_back( handler->body );
524 }
525 handling_code->push_back( new ast::ReturnStmt(loc,
526 ast::ConstantExpr::from_bool(loc, true ) ) );
527 handler->body = handling_code;
528
529 // Create the handler.
530 body->push_back( create_single_matcher( except_obj, handler ) );
531 *it = nullptr;
532 }
533
534 body->push_back( new ast::ReturnStmt(loc,
535 ast::ConstantExpr::from_bool(loc, false ) ) );
536 func_t->stmts = body;
537
538 return func_t;
539}
540
541ast::CompoundStmt * TryMutatorCore::create_resume_wrapper(
542 const ast::Stmt * wraps,
543 const ast::FunctionDecl * resume_handler ) {
544 const CodeLocation loc = wraps->location;
545 ast::CompoundStmt * body = new ast::CompoundStmt(loc);
546
547 // struct __try_resume_node __resume_node
548 // __attribute__((cleanup( __cfaehm_try_resume_cleanup )));
549 // ** unwinding of the stack here could cause problems **
550 // ** however I don't think that can happen currently **
551 // __cfaehm_try_resume_setup( &__resume_node, resume_handler );
552
553 ast::ObjectDecl * obj = new ast::ObjectDecl(
554 loc,
555 "__resume_node",
556 new ast::StructInstType(
557 node_decl
558 ),
559 nullptr,
560 ast::Storage::Classes{},
561 ast::Linkage::Cforall,
562 nullptr,
563 {new ast::Attribute("cleanup", {new ast::NameExpr(loc, "__cfaehm_try_resume_cleanup")})}
564 );
565 appendDeclStmt( body, obj );
566
567 ast::UntypedExpr *setup = new ast::UntypedExpr(loc, new ast::NameExpr(loc,
568 "__cfaehm_try_resume_setup" ) );
569 setup->args.push_back( new ast::AddressExpr( loc, new ast::VariableExpr(loc, obj ) ) );
570 setup->args.push_back( new ast::VariableExpr( loc, resume_handler ) );
571
572 body->push_back( new ast::ExprStmt(loc, setup ) );
573
574 body->push_back( wraps );
575 return body;
576}
577
578ast::FunctionDecl * TryMutatorCore::create_finally_wrapper(
579 ast::TryStmt * tryStmt ) {
580 // void finally() { `finally->block` }
581 const ast::FinallyClause * finally = tryStmt->finally;
582 const ast::CompoundStmt * body = finally->body;
583
584 ast::FunctionDecl * func_t = make_finally_function( tryStmt->location );
585 func_t->stmts = body;
586
587 tryStmt->finally = nullptr;
588
589 return func_t;
590}
591
592ast::ObjectDecl * TryMutatorCore::create_finally_hook(
593 ast::FunctionDecl * finally_wrapper ) {
594 // struct __cfaehm_cleanup_hook __finally_hook
595 // __attribute__((cleanup( `finally_wrapper` )));
596
597 const CodeLocation loc = finally_wrapper->location;
598 return new ast::ObjectDecl(
599 loc,
600 "__finally_hook",
601 new ast::StructInstType(
602 hook_decl
603 ),
604 nullptr,
605 ast::Storage::Classes{},
606 ast::Linkage::Cforall,
607 nullptr,
608 {new ast::Attribute("cleanup", {new ast::VariableExpr{loc, finally_wrapper}})}
609 );
610}
611
612ast::Stmt * TryMutatorCore::create_resume_rethrow( const ast::ThrowStmt *throwStmt ) {
613 // return false;
614 const CodeLocation loc = throwStmt->location;
615 ast::Stmt * result = new ast::ReturnStmt(loc,
616 ast::ConstantExpr::from_bool( loc, false )
617 );
618 result->labels = throwStmt->labels;
619 return result;
620}
621
622// Visiting/Mutating Functions
623void TryMutatorCore::previsit( const ast::StructDecl *structDecl ) {
624 if ( !structDecl->body ) {
625 // Skip children?
626 return;
627 } else if ( structDecl->name == "__cfaehm_base_exception_t" ) {
628 assert( nullptr == except_decl );
629 except_decl = structDecl;
630 } else if ( structDecl->name == "__cfaehm_try_resume_node" ) {
631 assert( nullptr == node_decl );
632 node_decl = structDecl;
633 } else if ( structDecl->name == "__cfaehm_cleanup_hook" ) {
634 assert( nullptr == hook_decl );
635 hook_decl = structDecl;
636 }
637}
638
639ast::Stmt * TryMutatorCore::postvisit( const ast::TryStmt *tryStmt ) {
640 assert( except_decl );
641 assert( node_decl );
642 assert( hook_decl );
643
644 const CodeLocation loc = tryStmt->location;
645 ast::TryStmt * mutStmt = mutate(tryStmt);
646 // Generate a prefix for the function names?
647
648 ast::CompoundStmt * block = new ast::CompoundStmt( loc );
649 // ast::CompoundStmt * inner = take_try_block( mutStmt );
650 // this is never mutated so let node deletion do its job?
651 const ast::CompoundStmt * inner = mutStmt->body;
652
653 if ( mutStmt->finally ) {
654 // Define the helper function.
655 ast::FunctionDecl * finally_block =
656 create_finally_wrapper( mutStmt );
657 appendDeclStmt( block, finally_block );
658 // Create and add the finally cleanup hook.
659 appendDeclStmt( block, create_finally_hook( finally_block ) );
660 }
661
662 CatchList termination_handlers;
663 CatchList resumption_handlers;
664
665 for (auto & handler: mutStmt->handlers) {
666 // xxx - should always be unique? mutate as safe const-cast
667 assert(handler->unique());
668 if (handler->kind == ast::ExceptionKind::Resume) {
669 resumption_handlers.push_back(handler.get_and_mutate());
670 }
671 else {
672 termination_handlers.push_back(handler.get_and_mutate());
673 }
674 }
675
676 if ( resumption_handlers.size() ) {
677 // Define the helper function.
678 ast::FunctionDecl * resume_handler =
679 create_resume_handler( resumption_handlers );
680 appendDeclStmt( block, resume_handler );
681 // Prepare hooks
682 inner = create_resume_wrapper( inner, resume_handler );
683 }
684
685 if ( termination_handlers.size() ) {
686 // Define the three helper functions.
687 ast::FunctionDecl * try_wrapper = create_try_wrapper( inner );
688 appendDeclStmt( block, try_wrapper );
689 ast::FunctionDecl * terminate_catch =
690 create_terminate_catch( termination_handlers );
691 appendDeclStmt( block, terminate_catch );
692 ast::FunctionDecl * terminate_match =
693 create_terminate_match( termination_handlers );
694 appendDeclStmt( block, terminate_match );
695 // Build the call to the try wrapper.
696 inner = create_terminate_caller(inner->location,
697 try_wrapper, terminate_catch, terminate_match );
698 }
699
700 // Embed the try block.
701 block->push_back( inner );
702
703 return block;
704}
705
706ast::Stmt * TryMutatorCore::postvisit( const ast::ThrowStmt *throwStmt ) {
707 // Only valid `throwResume;` statements should remain. (2/3 checks)
708 assert( ast::ExceptionKind::Resume == throwStmt->kind && ! throwStmt->expr );
709 return create_resume_rethrow( throwStmt );
710}
711
712} // namespace
713
714void translateThrows( ast::TranslationUnit & transUnit ) {
715 ast::Pass<TranslateThrowsCore>::run( transUnit );
716}
717
718void translateTries( ast::TranslationUnit & transUnit ) {
719 ast::Pass<TryMutatorCore>::run(transUnit);
720}
721
722} // namespace ControlStruct
723
724// Local Variables: //
725// tab-width: 4 //
726// mode: c++ //
727// compile-command: "make install" //
728// End: //
Note: See TracBrowser for help on using the repository browser.