Changeset 88bc876 for src


Ignore:
Timestamp:
Jul 16, 2024, 5:28:10 PM (3 days 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.

Location:
src
Files:
3 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        }
Note: See TracChangeset for help on using the changeset viewer.