Changeset 88bc876


Ignore:
Timestamp:
Jul 16, 2024, 5:28:10 PM (7 months ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
master
Children:
97f9619
Parents:
2363147
Message:

Breaks (and some other control flow) in a loop else clause now work. I also implemented else clauses in printing and code generation.

Files:
5 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Print.cpp

    r2363147 r88bc876  
    566566                ++indent;
    567567                safe_print( node->cond );
    568                 os << indent-1 << "... with body:" << endl;
    569                 safe_print( node->body );
    570568
    571569                if ( ! node->inits.empty() ) {
     
    573571                        printAll( node->inits );
    574572                }
     573
     574                os << indent-1 << "... with body:" << endl;
     575                safe_print( node->body );
     576
     577                if ( node->else_ ) {
     578                        os << indent-1 << "... with else:" << endl;
     579                        os << indent;
     580                        node->else_->accept( *this );
     581                }
     582
    575583                --indent;
    576584
     
    614622                        --indent;
    615623                }
     624
     625                if ( node->else_ ) {
     626                        os << indent << "... with else:" << endl;
     627                        ++indent;
     628                        os << indent;
     629                        node->else_->accept( *this );
     630                        --indent;
     631                }
     632
    616633                os << endl;
    617634                print( node->labels );
  • src/CodeGen/CodeGenerator.cpp

    r2363147 r88bc876  
    11951195        stmt->body->accept( *visitor );
    11961196
    1197         output << indent;
    1198 
    11991197        if ( stmt->isDoWhile ) {
    12001198                output << " while (";
    12011199                stmt->cond->accept( *visitor );
    1202                 output << ");";
     1200                output << ( ( nullptr == stmt->else_ ) ? ");" : ")" );
     1201        }
     1202        if ( stmt->else_ ) {
     1203                output << " else ";
     1204                stmt->else_->accept( *visitor );
    12031205        }
    12041206}
     
    12251227                stmt->body->accept( *visitor );
    12261228        }
     1229
     1230        if ( nullptr != stmt->else_ ) {
     1231                assertf( !options.genC, "Loop else should not reach code generation." );
     1232                output << " else ";
     1233                stmt->else_->accept( *visitor );
     1234        }
    12271235}
    12281236
  • src/ControlStruct/MultiLevelExit.cpp

    r2363147 r88bc876  
    7878                stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( TryStmtK ) {}
    7979
     80        // Check if this entry can be the target of the given type of control flow.
    8081        bool isContTarget() const { return kind <= WhileDoStmtK; }
    8182        bool isBreakTarget() const { return kind != CaseClauseK; }
     
    207208
    208209        // If the label is empty, do not add unused attribute.
    209   if ( originalTarget.empty() ) return size;
     210        if ( originalTarget.empty() ) return size;
    210211
    211212        // Search for a label that matches the originalTarget.
     
    343344                assert(0);
    344345        }
     346        assert( !exitLabel.empty() );
    345347
    346348        // Add unused attribute to silence warnings.
     
    486488                }
    487489
    488                 auto caseStmt = mutStmt->cases.back().get();
    489                 auto mutCase = mutate( caseStmt );
    490                 mutStmt->cases.back() = mutCase;
     490                auto mutCase = mutStmt->cases.back().get_and_mutate();
    491491
    492492                Label label( mutCase->location, "breakLabel" );
     
    597597template<typename LoopNode>
    598598void MultiLevelExitCore::prehandleLoopStmt( const LoopNode * loopStmt ) {
    599         // Remember is loop before going onto mutate the body.
     599        // Create temporary labels and mark the enclosing loop before traversal.
    600600        // The labels will be folded in if they are used.
    601601        Label breakLabel = newLabel( "loopBreak", loopStmt );
    602602        Label contLabel = newLabel( "loopContinue", loopStmt );
    603603        enclosing_control_structures.emplace_back( loopStmt, breakLabel, contLabel );
    604         // labels are added temporarily to see if they are used and then added permanently in postvisit if ther are used
    605         // children will tag labels as being used during their traversal which occurs before postvisit
    606 
    607         // GuardAction calls the lambda after the node is done being visited
     604
    608605        GuardAction( [this](){ enclosing_control_structures.pop_back(); } );
     606
     607        // Because of fixBlock, this should be empty now (and must be).
     608        assert( nullptr == loopStmt->else_ );
    609609}
    610610
     
    617617        // Now check if the labels are used and add them if so.
    618618        return mutate_field( loopStmt, &LoopNode::body, mutateLoop( loopStmt->body, entry ) );
    619         // this call to mutate_field compares loopStmt->body and the result of mutateLoop
    620         //              if they are the same the node isn't mutated, if they differ then the new mutated node is returned
    621         //              the stmts will only differ if a label is used
    622619}
    623620
     
    639636
    640637                ptr<Stmt> else_stmt = nullptr;
    641                 const Stmt * loop_kid = nullptr;
     638                const Stmt * to_visit;
    642639                // check if loop node and if so add else clause if it exists
    643                 const WhileDoStmt * whilePtr = kid.as<WhileDoStmt>();
    644                 if ( whilePtr && whilePtr->else_ ) {
    645                         else_stmt = whilePtr->else_;
    646                         loop_kid = mutate_field( whilePtr, &WhileDoStmt::else_, nullptr );
    647                 }
    648                 const ForStmt * forPtr = kid.as<ForStmt>();
    649                 if ( forPtr && forPtr->else_ ) {
    650                         else_stmt = forPtr->else_;
    651                         loop_kid = mutate_field( forPtr, &ForStmt::else_, nullptr );
    652                 }
    653 
     640                if ( auto ptr = kid.as<WhileDoStmt>() ; ptr && ptr->else_ ) {
     641                        else_stmt = ptr->else_;
     642                        to_visit = mutate_field( ptr, &WhileDoStmt::else_, nullptr );
     643                } else if ( auto ptr = kid.as<ForStmt>() ; ptr && ptr->else_ ) {
     644                        else_stmt = ptr->else_;
     645                        to_visit = mutate_field( ptr, &ForStmt::else_, nullptr );
     646                } else {
     647                        to_visit = kid.get();
     648                }
     649
     650                // This is the main (safe) visit of the child node.
    654651                try {
    655                         if (else_stmt) ret.push_back( loop_kid->accept( *visitor ) );
    656                         else ret.push_back( kid->accept( *visitor ) );
     652                        ret.push_back( to_visit->accept( *visitor ) );
    657653                } catch ( SemanticErrorException & e ) {
    658654                        errors.append( e );
    659655                }
    660656
    661                 if (else_stmt) ret.push_back(else_stmt);
    662 
    663                 if ( ! break_label.empty() ) {
     657                // The following sections handle visiting loop else clause and makes
     658                // sure breaking from a loop body does not execute that clause.
     659                Label local_break_label = std::move( break_label );
     660                break_label = Label( CodeLocation(), "" );
     661
     662                if ( else_stmt ) try {
     663                        ret.push_back( else_stmt->accept( *visitor ) );
     664                } catch ( SemanticErrorException & e ) {
     665                        errors.append( e );
     666                }
     667
     668                if ( !break_label.empty() ) {
    664669                        ret.push_back( labelledNullStmt( ret.back()->location, break_label ) );
    665670                        break_label = Label( CodeLocation(), "" );
    666671                }
    667         }
    668 
    669         if ( ! errors.isEmpty() ) {
     672
     673                // This handles a break from the body or non-loop statement.
     674                if ( !local_break_label.empty() ) {
     675                        ret.push_back( labelledNullStmt( ret.back()->location, local_break_label ) );
     676                }
     677        }
     678
     679        if ( !errors.isEmpty() ) {
    670680                throw errors;
    671681        }
  • tests/ctrl-flow/.expect/loop_else.txt

    r2363147 r88bc876  
    6363(10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0)else
    6464
     65before begin else after
  • tests/ctrl-flow/loop_else.cfa

    r2363147 r88bc876  
    7474                i -= 1.7;
    7575        } else { sout | "else"; }                                                                                                               sout | nl | nl;
    76        
     76
    7777        enum { N = 10 };
    7878        for ( N ) { sout | "N"; } else { sout | "else"; }                                                       sout | nl;
     
    109109        for ( s; (S){0} -~  (S){10,10} ~ (S){1} ) { sout | s; } else { sout | "else"; } sout | nl;
    110110        for ( s; (S){0} -~= (S){10,10} ) { sout | s; } else { sout | "else"; }           sout | nl;
    111         for ( s; (S){0} -~= (S){10,10} ~ (S){1} ) { sout | s; } else { sout | "else"; } sout | nl | nl;
     111        for ( s; (S){0} -~= (S){10,10} ~ (S){1} ) { sout | s; } else { sout | "else"; } sout | nl;
     112        sout | nl;
     113
     114        // A break (or a continue) in an else clause should target an outer loop.
     115        sout | "before";
     116        while ( true ) {
     117                sout | " begin";
     118                while ( false ) {
     119                        sout | "never";
     120                } else {
     121                        sout | " else";
     122                        break;
     123                }
     124                sout | " end";
     125        }
     126        sout | " after" | nl;
    112127}
Note: See TracChangeset for help on using the changeset viewer.