Changes in / [0188539c:8d26b7a]


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Tuples/TupleAssignment.cpp

    r0188539c r8d26b7a  
    241241        ResolvExpr::CandidateFinder & crntFinder;
    242242        std::string fname;
     243        std::unique_ptr< Matcher > matcher;
    243244
    244245public:
    245246        TupleAssignSpotter( ResolvExpr::CandidateFinder & f )
    246         : crntFinder( f ), fname() {}
    247 
    248         /// Find left- and right-hand-sides for mass or multiple assignment.
     247        : crntFinder( f ), fname(), matcher() {}
     248
     249        // Find left- and right-hand-sides for mass or multiple assignment.
    249250        void spot(
    250251                const ast::UntypedExpr * expr, std::vector< ResolvExpr::CandidateFinder > & args
    251         );
    252         /// Wrapper around matcher.match.
    253         void match( Matcher & matcher );
     252        ) {
     253                if ( auto op = expr->func.as< ast::NameExpr >() ) {
     254                        // Skip non-assignment functions.
     255                        if ( !CodeGen::isCtorDtorAssign( op->name ) ) return;
     256                        fname = op->name;
     257
     258                        // Handled by CandidateFinder if applicable (both odd cases).
     259                        if ( args.empty() || ( 1 == args.size() && CodeGen::isAssignment( fname ) ) ) {
     260                                return;
     261                        }
     262
     263                        // Look over all possible left-hand-side.
     264                        for ( ResolvExpr::CandidateRef & lhsCand : args[0] ) {
     265                                // Skip non-tuple LHS.
     266                                if ( !refToTuple( lhsCand->expr ) ) continue;
     267
     268                                // Explode is aware of casts - ensure every LHS
     269                                // is sent into explode with a reference cast.
     270                                if ( !lhsCand->expr.as< ast::CastExpr >() ) {
     271                                        lhsCand->expr = new ast::CastExpr(
     272                                                lhsCand->expr, new ast::ReferenceType( lhsCand->expr->result ) );
     273                                }
     274
     275                                // Explode the LHS so that each field of a tuple-valued expr is assigned.
     276                                ResolvExpr::CandidateList lhs;
     277                                explode( *lhsCand, crntFinder.context.symtab, back_inserter(lhs), true );
     278                                for ( ResolvExpr::CandidateRef & cand : lhs ) {
     279                                        // Each LHS value must be a reference - some come in
     280                                        // with a cast, if not just cast to reference here.
     281                                        if ( !cand->expr->result.as< ast::ReferenceType >() ) {
     282                                                cand->expr = new ast::CastExpr(
     283                                                        cand->expr, new ast::ReferenceType( cand->expr->result ) );
     284                                        }
     285                                }
     286
     287                                if ( 1 == args.size() ) {
     288                                        // Mass default-initialization/destruction.
     289                                        ResolvExpr::CandidateList rhs{};
     290                                        matcher.reset( new MassAssignMatcher( *this, expr->location, lhs, rhs ) );
     291                                        match();
     292                                } else if ( 2 == args.size() ) {
     293                                        for ( const ResolvExpr::CandidateRef & rhsCand : args[1] ) {
     294                                                ResolvExpr::CandidateList rhs;
     295                                                if ( isTuple( rhsCand->expr ) ) {
     296                                                        // Multiple assignment:
     297                                                        explode( *rhsCand, crntFinder.context.symtab, back_inserter( rhs ), true );
     298                                                        matcher.reset(
     299                                                                new MultipleAssignMatcher( *this, expr->location, lhs, rhs ) );
     300                                                } else {
     301                                                        // Mass assignment:
     302                                                        rhs.emplace_back( rhsCand );
     303                                                        matcher.reset(
     304                                                                new MassAssignMatcher( *this, expr->location, lhs, rhs ) );
     305                                                }
     306                                                match();
     307                                        }
     308                                } else {
     309                                        // Expand all possible RHS possibilities.
     310                                        std::vector< ResolvExpr::CandidateList > rhsCands;
     311                                        combos(
     312                                                std::next( args.begin(), 1 ), args.end(), back_inserter( rhsCands ) );
     313                                        for ( const ResolvExpr::CandidateList & rhsCand : rhsCands ) {
     314                                                // Multiple assignment:
     315                                                ResolvExpr::CandidateList rhs;
     316                                                explode( rhsCand, crntFinder.context.symtab, back_inserter( rhs ), true );
     317                                                matcher.reset(
     318                                                        new MultipleAssignMatcher( *this, expr->location, lhs, rhs ) );
     319                                                match();
     320                                        }
     321                                }
     322                        }
     323                }
     324        }
     325
     326        void match() {
     327                assert( matcher );
     328
     329                std::vector< ast::ptr< ast::Expr > > newAssigns = matcher->match();
     330
     331                if ( !( matcher->lhs.empty() && matcher->rhs.empty() ) ) {
     332                        // If both LHS and RHS are empty than this is the empty tuple
     333                        // case, wherein it's okay for newAssigns to be empty. Otherwise,
     334                        // return early so that no new candidates are generated.
     335                        if ( newAssigns.empty() ) return;
     336                }
     337
     338                ResolvExpr::CandidateList crnt;
     339                // Now resolve new assignments.
     340                for ( const ast::Expr * expr : newAssigns ) {
     341                        PRINT(
     342                                std::cerr << "== resolving tuple assign ==" << std::endl;
     343                                std::cerr << expr << std::endl;
     344                        )
     345
     346                        ResolvExpr::CandidateFinder finder( crntFinder.context, matcher->env );
     347                        finder.allowVoid = true;
     348
     349                        try {
     350                                finder.find( expr, ResolvExpr::ResolveMode::withAdjustment() );
     351                        } catch (...) {
     352                                // No match is not failure, just that this tuple assignment is invalid.
     353                                return;
     354                        }
     355
     356                        ResolvExpr::CandidateList & cands = finder.candidates;
     357                        assert( 1 == cands.size() );
     358                        assert( cands.front()->expr );
     359                        crnt.emplace_back( std::move( cands.front() ) );
     360                }
     361
     362                // extract expressions from the assignment candidates to produce a list of assignments
     363                // that together form a sigle candidate
     364                std::vector< ast::ptr< ast::Expr > > solved;
     365                for ( ResolvExpr::CandidateRef & cand : crnt ) {
     366                        solved.emplace_back( cand->expr );
     367                        matcher->combineState( *cand );
     368                }
     369
     370                crntFinder.candidates.emplace_back( std::make_shared< ResolvExpr::Candidate >(
     371                        new ast::TupleAssignExpr(
     372                                matcher->location, std::move( solved ), std::move( matcher->tmpDecls ) ),
     373                        std::move( matcher->env ), std::move( matcher->open ), std::move( matcher->need ),
     374                        ResolvExpr::sumCost( crnt ) + matcher->baseCost ) );
     375        }
    254376};
    255 
    256 void TupleAssignSpotter::spot(
    257         const ast::UntypedExpr * expr, std::vector< ResolvExpr::CandidateFinder > & args
    258 ) {
    259         // Skip non-"assignment" functions.
    260         auto op = expr->func.as< ast::NameExpr >();
    261         if ( nullptr == op || !CodeGen::isCtorDtorAssign( op->name ) ) return;
    262 
    263         // Handled by CandidateFinder if applicable (both odd cases).
    264         if ( args.empty() || ( 1 == args.size() && CodeGen::isAssignment( op->name ) ) ) {
    265                 return;
    266         }
    267 
    268         fname = op->name;
    269 
    270         // Look over all possible left-hand-side.
    271         for ( ResolvExpr::CandidateRef & lhsCand : args[0] ) {
    272                 // Skip non-tuple LHS.
    273                 if ( !refToTuple( lhsCand->expr ) ) continue;
    274 
    275                 // Explode is aware of casts - ensure every LHS
    276                 // is sent into explode with a reference cast.
    277                 if ( !lhsCand->expr.as< ast::CastExpr >() ) {
    278                         lhsCand->expr = new ast::CastExpr(
    279                                 lhsCand->expr, new ast::ReferenceType( lhsCand->expr->result ) );
    280                 }
    281 
    282                 // Explode the LHS so that each field of a tuple-valued expr is assigned.
    283                 ResolvExpr::CandidateList lhs;
    284                 explode( *lhsCand, crntFinder.context.symtab, back_inserter(lhs), true );
    285                 for ( ResolvExpr::CandidateRef & cand : lhs ) {
    286                         // Each LHS value must be a reference - some come in
    287                         // with a cast, if not just cast to reference here.
    288                         if ( !cand->expr->result.as< ast::ReferenceType >() ) {
    289                                 cand->expr = new ast::CastExpr(
    290                                         cand->expr, new ast::ReferenceType( cand->expr->result ) );
    291                         }
    292                 }
    293 
    294                 if ( 1 == args.size() ) {
    295                         // Mass default-initialization/destruction.
    296                         ResolvExpr::CandidateList rhs{};
    297                         MassAssignMatcher matcher( *this, expr->location, lhs, rhs );
    298                         match( matcher );
    299                 } else if ( 2 == args.size() ) {
    300                         for ( const ResolvExpr::CandidateRef & rhsCand : args[1] ) {
    301                                 ResolvExpr::CandidateList rhs;
    302                                 if ( isTuple( rhsCand->expr ) ) {
    303                                         // Multiple assignment:
    304                                         explode( *rhsCand, crntFinder.context.symtab, back_inserter( rhs ), true );
    305                                         MultipleAssignMatcher matcher( *this, expr->location, lhs, rhs );
    306                                         match( matcher );
    307                                 } else {
    308                                         // Mass assignment:
    309                                         rhs.emplace_back( rhsCand );
    310                                         MassAssignMatcher matcher( *this, expr->location, lhs, rhs );
    311                                         match( matcher );
    312                                 }
    313                         }
    314                 } else {
    315                         // Expand all possible RHS possibilities.
    316                         std::vector< ResolvExpr::CandidateList > rhsCands;
    317                         combos(
    318                                 std::next( args.begin(), 1 ), args.end(), back_inserter( rhsCands ) );
    319                         for ( const ResolvExpr::CandidateList & rhsCand : rhsCands ) {
    320                                 // Multiple assignment:
    321                                 ResolvExpr::CandidateList rhs;
    322                                 explode( rhsCand, crntFinder.context.symtab, back_inserter( rhs ), true );
    323                                 MultipleAssignMatcher matcher( *this, expr->location, lhs, rhs );
    324                                 match( matcher );
    325                         }
    326                 }
    327         }
    328 }
    329 
    330 void TupleAssignSpotter::match( TupleAssignSpotter::Matcher & matcher ) {
    331         std::vector< ast::ptr< ast::Expr > > newAssigns = matcher.match();
    332 
    333         if ( !( matcher.lhs.empty() && matcher.rhs.empty() ) ) {
    334                 // If both LHS and RHS are empty than this is the empty tuple
    335                 // case, wherein it's okay for newAssigns to be empty. Otherwise,
    336                 // return early so that no new candidates are generated.
    337                 if ( newAssigns.empty() ) return;
    338         }
    339 
    340         ResolvExpr::CandidateList crnt;
    341         // Now resolve new assignments.
    342         for ( const ast::Expr * expr : newAssigns ) {
    343                 PRINT(
    344                         std::cerr << "== resolving tuple assign ==" << std::endl;
    345                         std::cerr << expr << std::endl;
    346                 )
    347 
    348                 ResolvExpr::CandidateFinder finder( crntFinder.context, matcher.env );
    349                 finder.allowVoid = true;
    350 
    351                 try {
    352                         finder.find( expr, ResolvExpr::ResolveMode::withAdjustment() );
    353                 } catch (...) {
    354                         // No match is not failure, just that this tuple assignment is invalid.
    355                         return;
    356                 }
    357 
    358                 ResolvExpr::CandidateList & cands = finder.candidates;
    359                 assert( 1 == cands.size() );
    360                 assert( cands.front()->expr );
    361                 crnt.emplace_back( std::move( cands.front() ) );
    362         }
    363 
    364         // extract expressions from the assignment candidates to produce a list of assignments
    365         // that together form a sigle candidate
    366         std::vector< ast::ptr< ast::Expr > > solved;
    367         for ( ResolvExpr::CandidateRef & cand : crnt ) {
    368                 solved.emplace_back( cand->expr );
    369                 matcher.combineState( *cand );
    370         }
    371 
    372         crntFinder.candidates.emplace_back( std::make_shared< ResolvExpr::Candidate >(
    373                 new ast::TupleAssignExpr(
    374                         matcher.location, std::move( solved ), std::move( matcher.tmpDecls ) ),
    375                 std::move( matcher.env ), std::move( matcher.open ), std::move( matcher.need ),
    376                 ResolvExpr::sumCost( crnt ) + matcher.baseCost ) );
    377 }
    378377
    379378} // anonymous namespace
Note: See TracChangeset for help on using the changeset viewer.