Ignore:
Timestamp:
Jun 28, 2016, 3:33:01 PM (8 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, ctor, deferred_resn, demangler, enum, forall-pointer-decay, gc_noraii, jacob/cs343-translation, jenkins-sandbox, master, memory, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
4dcea3f
Parents:
888cbe4
Message:

overhaul MLE code, attach label to break/continue statements so it can be used to generate dtor calls, mutate continue statements into goto statements so dtor generation works correctly

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ControlStruct/MLEMutator.cc

    r888cbe4 re39aa0f  
    2727#include "SynTree/Statement.h"
    2828#include "SynTree/Expression.h"
     29#include "SynTree/Attribute.h"
    2930
    3031namespace ControlStruct {
     
    3233                delete targetTable;
    3334                targetTable = 0;
     35        }
     36        namespace {
     37                Statement * isLoop( Statement * stmt ) { return dynamic_cast< WhileStmt * >( stmt ) ? stmt : dynamic_cast< ForStmt * >( stmt ) ? stmt : 0; }
    3438        }
    3539
     
    4448                        if ( ! get_breakLabel().empty() ) {
    4549                                std::list< Statement * >::iterator next = k+1;
    46                                 Statement * stmt = 0;
    47                                 if ( next == kids.end() ) {
    48                                         std::list<Label> ls; ls.push_back( get_breakLabel() );
    49                                         kids.push_back( stmt = new NullStmt( ls ) );
    50                                 } else {
    51                                         (stmt = *next)->get_labels().push_back( get_breakLabel() );
    52                                 }
    53                                 stmt->get_labels().front().set_statement( stmt );
    54 
     50                                std::list<Label> ls; ls.push_back( get_breakLabel() );
     51                                kids.insert( next, new NullStmt( ls ) );
    5552                                set_breakLabel("");
    5653                        } // if
     
    6259                if ( labeledBlock ) {
    6360                        Label brkLabel = generator->newLabel("blockBreak");
    64                         enclosingBlocks.push_back( Entry( cmpndStmt, brkLabel ) );
     61                        enclosingControlStructures.push_back( Entry( cmpndStmt, brkLabel ) );
    6562                } // if
    6663
     
    7168
    7269                if ( labeledBlock ) {
    73                         assert( ! enclosingBlocks.empty() );
    74                         if ( ! enclosingBlocks.back().useBreakExit().empty() ) {
    75                                 set_breakLabel( enclosingBlocks.back().useBreakExit() );
    76                         }
    77                         enclosingBlocks.pop_back();
     70                        assert( ! enclosingControlStructures.empty() );
     71                        if ( ! enclosingControlStructures.back().useBreakExit().empty() ) {
     72                                set_breakLabel( enclosingControlStructures.back().useBreakExit() );
     73                        }
     74                        enclosingControlStructures.pop_back();
    7875                } // if
    7976
     
    8986                Label brkLabel = generator->newLabel("loopBreak");
    9087                Label contLabel = generator->newLabel("loopContinue");
    91                 enclosingLoops.push_back( Entry( loopStmt, brkLabel, contLabel ) );
     88                enclosingControlStructures.push_back( Entry( loopStmt, brkLabel, contLabel ) );
    9289                loopStmt->set_body ( loopStmt->get_body()->acceptMutator( *this ) );
    9390
    9491                // sanity check that the enclosing loops have been popped correctly
    95                 Entry &e = enclosingLoops.back();
     92                Entry &e = enclosingControlStructures.back();
    9693                assert ( e == loopStmt );
    9794
     
    9996                // two labels, if they are used.
    10097                loopStmt->set_body( mutateLoop( loopStmt->get_body(), e ) );
    101                 enclosingLoops.pop_back();
     98                enclosingControlStructures.pop_back();
    10299
    103100                return loopStmt;
     
    115112                // generate a label for breaking out of a labeled switch
    116113                Label brkLabel = generator->newLabel("switchBreak");
    117                 enclosingSwitches.push_back( Entry(switchStmt, brkLabel) );
     114                enclosingControlStructures.push_back( Entry(switchStmt, brkLabel) );
    118115                mutateAll( switchStmt->get_branches(), *this );
    119116
    120                 Entry &e = enclosingSwitches.back();
     117                Entry &e = enclosingControlStructures.back();
    121118                assert ( e == switchStmt );
    122119
     
    133130                        if ( CaseStmt * c = dynamic_cast< CaseStmt * >( branches.back() ) ) {
    134131                                std::list<Label> temp; temp.push_back( brkLabel );
    135                                 Statement * stmt = new BranchStmt( temp, Label(""), BranchStmt::Break );
    136                                 stmt->get_labels().front().set_statement( stmt );
    137                                 c->get_statements().push_back( stmt );
     132                                c->get_statements().push_back( new BranchStmt( temp, Label("brkLabel"), BranchStmt::Break ) );
    138133                        } else assert(0); // as of this point, all branches of a switch are still CaseStmts
    139134                }
    140135
    141                 assert ( enclosingSwitches.back() == switchStmt );
    142                 enclosingSwitches.pop_back();
     136                assert ( enclosingControlStructures.back() == switchStmt );
     137                enclosingControlStructures.pop_back();
    143138                return switchStmt;
    144139        }
     
    147142                std::string originalTarget = branchStmt->get_originalTarget();
    148143
    149                 if ( branchStmt->get_type() == BranchStmt::Goto )
     144                std::list< Entry >::reverse_iterator targetEntry;
     145                if ( branchStmt->get_type() == BranchStmt::Goto ) {
    150146                        return branchStmt;
    151 
    152                 // test if continue target is a loop
    153                 if ( branchStmt->get_type() == BranchStmt::Continue) {
    154                         if ( enclosingLoops.empty() ) {
    155                                 throw SemanticError( "'continue' outside a loop" );
    156                         } else if ( branchStmt->get_target() != "" && std::find( enclosingLoops.begin(), enclosingLoops.end(), (*targetTable)[branchStmt->get_target()] ) == enclosingLoops.end() ) {
    157                                 throw SemanticError( "'continue' target label must be an enclosing loop: " + originalTarget );
    158                         }
    159                 }
    160 
    161                 if ( branchStmt->get_type() == BranchStmt::Break && (enclosingLoops.empty() && enclosingSwitches.empty() && enclosingBlocks.empty() ) )
    162                         throw SemanticError( "'break' outside a loop or switch" );
    163 
    164                 if ( branchStmt->get_target() == "" ) return branchStmt;
    165 
    166                 if ( targetTable->find( branchStmt->get_target() ) == targetTable->end() )
     147                } else if ( branchStmt->get_type() == BranchStmt::Continue) {
     148                        // continue target must be a loop
     149                        if ( branchStmt->get_target() == "" ) {
     150                                targetEntry = std::find_if( enclosingControlStructures.rbegin(), enclosingControlStructures.rend(), [](Entry &e) { return isLoop( e.get_controlStructure() ); } );
     151                        } else {
     152                                // labelled continue - lookup label in table ot find attached control structure
     153                                targetEntry = std::find( enclosingControlStructures.rbegin(), enclosingControlStructures.rend(), (*targetTable)[branchStmt->get_target()] );
     154                        }
     155                        if ( targetEntry == enclosingControlStructures.rend() || ! isLoop( targetEntry->get_controlStructure() ) ) {
     156                                throw SemanticError( "'continue' target must be an enclosing loop: " + originalTarget );
     157                        }
     158                } else if ( branchStmt->get_type() == BranchStmt::Break ) {
     159                        if ( enclosingControlStructures.empty() ) throw SemanticError( "'break' outside a loop, switch, or labelled block" );
     160                        targetEntry = enclosingControlStructures.rbegin();
     161                } else {
     162                        assert( false );
     163                }
     164
     165                if ( branchStmt->get_target() != "" && targetTable->find( branchStmt->get_target() ) == targetTable->end() ) {
    167166                        throw SemanticError("The label defined in the exit loop statement does not exist: " + originalTarget );  // shouldn't happen (since that's already checked)
    168 
    169                 std::list< Entry >::iterator check;
    170                 if ( ( check = std::find( enclosingLoops.begin(), enclosingLoops.end(), (*targetTable)[branchStmt->get_target()] ) ) == enclosingLoops.end() )
    171                         // not in loop, checking if in block
    172                         if ( (check = std::find( enclosingBlocks.begin(), enclosingBlocks.end(), (*targetTable)[branchStmt->get_target()] )) == enclosingBlocks.end() )
    173                                 // neither in loop nor in block, checking if in switch/choose
    174                                 if ( (check = std::find( enclosingSwitches.begin(), enclosingSwitches.end(), (*targetTable)[branchStmt->get_target()] )) == enclosingSwitches.end() )
    175                                         throw SemanticError("The target specified in the exit loop statement does not correspond to an enclosing control structure: " + originalTarget );
    176 
     167                }
     168
     169                // xxx - possibly remove this
    177170                // what about exiting innermost block or switch???
    178                 if ( enclosingLoops.back() == (*check) )
    179                         return branchStmt;                              // exit the innermost loop (labels unnecessary)
     171                // if ( enclosingControlStructures.back() == (*targetEntry) )
     172                //      return branchStmt;                              // exit the innermost loop (labels unnecessary)
    180173
    181174                // branch error checks, get the appropriate label name and create a goto
     
    183176                switch ( branchStmt->get_type() ) {
    184177                  case BranchStmt::Break:
    185                                 assert( check->useBreakExit() != "");
    186                                 exitLabel = check->useBreakExit();
     178                                assert( targetEntry->useBreakExit() != "");
     179                                exitLabel = targetEntry->useBreakExit();
    187180                                break;
    188181                  case BranchStmt::Continue:
    189                                 assert( check->useContExit() != "");
    190                                 exitLabel = check->useContExit();
     182                                assert( targetEntry->useContExit() != "");
     183                                exitLabel = targetEntry->useContExit();
    191184                                break;
    192185                  default:
     
    194187                } // switch
    195188
    196                 return new BranchStmt( std::list<Label>(), exitLabel, BranchStmt::Goto );
     189                if ( branchStmt->get_target() == "" && branchStmt->get_type() != BranchStmt::Continue ) {
     190                        // unlabelled break/continue - can keep branch as break/continue for extra semantic information, but add
     191                        // exitLabel as its destination so that label passes can easily determine where the break/continue goes to
     192                        branchStmt->set_target( exitLabel );
     193                        return branchStmt;
     194                } else {
     195                        // labelled break/continue - can't easily emulate this with break and continue, so transform into a goto
     196                        delete branchStmt;
     197                        return new BranchStmt( std::list<Label>(), exitLabel, BranchStmt::Goto );
     198                }
    197199        }
    198200
     
    210212                        // continue label goes in the body as the last statement
    211213                        std::list< Label > labels; labels.push_back( e.useContExit() );
    212                         Statement * stmt = new NullStmt( labels );
    213                         stmt->get_labels().front().set_statement( stmt );
    214                         newBody->get_kids().push_back( stmt );
     214                        newBody->get_kids().push_back( new NullStmt( labels ) );
    215215                }
    216216
Note: See TracChangeset for help on using the changeset viewer.