Ignore:
Timestamp:
Sep 22, 2016, 8:14:56 AM (8 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
ac9ca96
Parents:
1132b62
git-author:
Rob Schluntz <rschlunt@…> (09/21/16 23:43:37)
git-committer:
Rob Schluntz <rschlunt@…> (09/22/16 08:14:56)
Message:

replace multiple-returning functions with tuple-returning functions, implement tuple ctor/dtor, allow N-arg tuple assignment

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Tuples/TupleAssignment.cc

    r1132b62 r65660bd  
    2121#include "Tuples.h"
    2222#include "Common/SemanticError.h"
     23#include "InitTweak/InitTweak.h"
    2324
    2425#include <functional>
     
    3536                // dispatcher for Tuple (multiple and mass) assignment operations
    3637                TupleAssignSpotter( ResolvExpr::AlternativeFinder & );
    37                 void spot( UntypedExpr * expr, std::list<ResolvExpr::AltList> &possibilities );
     38                void spot( UntypedExpr * expr, const std::list<ResolvExpr::AltList> &possibilities );
    3839
    3940          private:
     
    4243                struct Matcher {
    4344                  public:
    44                         Matcher( TupleAssignSpotter &spotter, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs );
     45                        Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts );
    4546                        virtual ~Matcher() {}
    4647                        virtual void match( std::list< Expression * > &out ) = 0;
     
    5253                struct MassAssignMatcher : public Matcher {
    5354                  public:
    54                         MassAssignMatcher( TupleAssignSpotter &spotter, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs );
     55                        MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts );
    5556                        virtual void match( std::list< Expression * > &out );
    5657                };
     
    5859                struct MultipleAssignMatcher : public Matcher {
    5960                  public:
    60                         MultipleAssignMatcher( TupleAssignSpotter &spot, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs );
     61                        MultipleAssignMatcher( TupleAssignSpotter &spot, const ResolvExpr::AltList & alts );
    6162                        virtual void match( std::list< Expression * > &out );
    6263                };
    6364
    6465                ResolvExpr::AlternativeFinder &currentFinder;
    65                 // Expression *rhs, *lhs;
    66                 Matcher *matcher = nullptr;
     66                std::string fname;
     67                std::unique_ptr< Matcher > matcher;
    6768        };
    6869
     
    7475        }
    7576
     77        template< typename AltIter >
     78        bool isMultAssign( AltIter begin, AltIter end ) {
     79                // multiple assignment if more than one alternative in the range or if
     80                // the alternative is a tuple
     81                if ( begin == end ) return false;
     82                if ( isTuple( begin->expr ) ) return true;
     83                return ++begin != end;
     84        }
     85
    7686        bool pointsToTuple( Expression *expr ) {
    7787                // also check for function returning tuple of reference types
    78                 if ( AddressExpr *addr = dynamic_cast< AddressExpr * >( expr) ) {
     88                if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
     89                        return pointsToTuple( castExpr->get_arg() );
     90                } else if ( AddressExpr *addr = dynamic_cast< AddressExpr * >( expr) ) {
    7991                        return isTuple( addr->get_arg() );
    8092                }
     
    8294        }
    8395
    84         void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr, std::list<ResolvExpr::AltList> &possibilities ) {
     96        void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr, const std::list<ResolvExpr::AltList> &possibilities ) {
    8597                TupleAssignSpotter spotter( currentFinder );
    8698                spotter.spot( expr, possibilities );
     
    90102                : currentFinder(f) {}
    91103
    92         void TupleAssignSpotter::spot( UntypedExpr * expr, std::list<ResolvExpr::AltList> &possibilities ) {
    93                 if (  NameExpr *assgnop = dynamic_cast< NameExpr * >(expr->get_function()) ) {
    94                         if ( assgnop->get_name() == "?=?" ) {
    95                                 for ( std::list<ResolvExpr::AltList>::iterator ali = possibilities.begin(); ali != possibilities.end(); ++ali ) {
    96                                         if ( ali->size() != 2 ) continue; // what does it mean if an assignment takes >2 arguments? grab args 2-N and group into a TupleExpr, then proceed?
    97                                         ResolvExpr::Alternative & alt1 = ali->front(), & alt2 = ali->back();
    98 
     104        void TupleAssignSpotter::spot( UntypedExpr * expr, const std::list<ResolvExpr::AltList> &possibilities ) {
     105                if (  NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {
     106                        if ( InitTweak::isCtorDtorAssign( op->get_name() ) ) {
     107                                fname = op->get_name();
     108                                for ( std::list<ResolvExpr::AltList>::const_iterator ali = possibilities.begin(); ali != possibilities.end(); ++ali ) {
     109                                        if ( ali->size() == 0 ) continue; // AlternativeFinder will natrually handle this case, if it's legal
     110                                        if ( ali->size() <= 1 && InitTweak::isAssignment( op->get_name() ) ) {
     111                                                // what does it mean if an assignment takes 1 argument? maybe someone defined such a function, in which case AlternativeFinder will naturally handle it
     112                                                continue;
     113                                        }
     114
     115                                        assert( ! ali->empty() );
     116                                        // grab args 2-N and group into a TupleExpr
     117                                        const ResolvExpr::Alternative & alt1 = ali->front();
     118                                        auto begin = std::next(ali->begin(), 1), end = ali->end();
    99119                                        if ( pointsToTuple(alt1.expr) ) {
    100                                                 MultipleAssignMatcher multiMatcher( *this, alt1, alt2 );
    101                                                 MassAssignMatcher massMatcher( *this,  alt1, alt2 );
    102                                                 if ( isTuple( alt2.expr ) ) {
    103                                                         matcher = &multiMatcher;
     120                                                if ( isMultAssign( begin, end ) ) {
     121                                                        matcher.reset( new MultipleAssignMatcher( *this, *ali ) );
    104122                                                } else {
    105123                                                        // mass assignment
    106                                                         matcher = &massMatcher;
     124                                                        matcher.reset( new MassAssignMatcher( *this,  *ali ) );
    107125                                                }
    108126                                                match();
    109                                         } else if ( isTuple( alt2.expr ) ) {
    110                                                 throw SemanticError("Cannot assign a tuple value into a non-tuple lvalue.", expr);
    111127                                        }
    112128                                }
     
    146162        }
    147163
    148         TupleAssignSpotter::Matcher::Matcher( TupleAssignSpotter &spotter, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs ) : spotter(spotter) {
    149                 if (AddressExpr *addr = dynamic_cast<AddressExpr *>(lhs.expr) ) {
    150                         // xxx - not every assignment NEEDS to have the first argument as address-taken, e.g. a manual call to assignment. What to do in this case? skip it as a possibility for TupleAssignment, since the type will always be T*, where T can never be a tuple? Is this true?
    151 
    152                         // explode the lhs so that each field of the tuple-valued-expr is assigned.
    153                         ResolvExpr::Alternative lhsAlt( addr->get_arg()->clone(), lhs.env, lhs.cost, lhs.cvtCost );
    154                         explode( lhsAlt, back_inserter(this->lhs) );
    155                 }
    156         }
    157 
    158         TupleAssignSpotter::MassAssignMatcher::MassAssignMatcher( TupleAssignSpotter &spotter, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs ) : Matcher( spotter, lhs, rhs ) {
    159                 this->rhs.push_back( rhs );
    160         }
    161 
    162         TupleAssignSpotter::MultipleAssignMatcher::MultipleAssignMatcher( TupleAssignSpotter &spotter, ResolvExpr::Alternative & lhs, ResolvExpr::Alternative & rhs ) : Matcher( spotter, lhs, rhs ) {
    163 
     164        TupleAssignSpotter::Matcher::Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList &alts ) : spotter(spotter) {
     165                assert( ! alts.empty() );
     166                ResolvExpr::Alternative lhsAlt = alts.front();
     167                // peel off the cast that exists on ctor/dtor expressions
     168                bool isCast = false;
     169                if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( lhsAlt.expr ) ) {
     170                        lhsAlt.expr = castExpr->get_arg();
     171                        castExpr->set_arg( nullptr );
     172                        delete castExpr;
     173                        isCast = true;
     174                }
     175
     176                // explode the lhs so that each field of the tuple-valued-expr is assigned.
     177                explode( lhsAlt, back_inserter(lhs) );
     178                // and finally, re-add the cast to each lhs expr, so that qualified tuple fields can be constructed
     179                if ( isCast ) {
     180                        for ( ResolvExpr::Alternative & alt : lhs ) {
     181                                Expression *& expr = alt.expr;
     182                                Type * castType = expr->get_result()->clone();
     183                                Type * type = InitTweak::getPointerBase( castType );
     184                                assert( type );
     185                                type->get_qualifiers() -= Type::Qualifiers(true, true, true, false, true, true);
     186                                type->set_isLvalue( true ); // xxx - might not need this
     187                                expr = new CastExpr( expr, castType );
     188                        }
     189                }
     190                // }
     191        }
     192
     193        TupleAssignSpotter::MassAssignMatcher::MassAssignMatcher( TupleAssignSpotter &spotter,const ResolvExpr::AltList & alts ) : Matcher( spotter, alts ) {
     194                assert( alts.size() == 1 || alts.size() == 2 );
     195                if ( alts.size() == 2 ) {
     196                        rhs.push_back( alts.back() );
     197                }
     198        }
     199
     200        TupleAssignSpotter::MultipleAssignMatcher::MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts ) : Matcher( spotter, alts ) {
    164201                // explode the rhs so that each field of the tuple-valued-expr is assigned.
    165                 explode( rhs, back_inserter(this->rhs) );
    166         }
    167 
    168         UntypedExpr * createAssgn( ObjectDecl *left, ObjectDecl *right ) {
    169                 assert( left && right );
     202                explode( std::next(alts.begin(), 1), alts.end(), back_inserter(rhs) );
     203        }
     204
     205        UntypedExpr * createFunc( const std::string &fname, ObjectDecl *left, ObjectDecl *right ) {
     206                assert( left );
    170207                std::list< Expression * > args;
    171208                args.push_back( new AddressExpr( new UntypedExpr( new NameExpr("*?"), std::list< Expression * >{ new VariableExpr( left ) } ) ) );
    172                 args.push_back( new VariableExpr( right ) );
    173                 return new UntypedExpr( new NameExpr( "?=?" ), args );
     209                // args.push_back( new AddressExpr( new VariableExpr( left ) ) );
     210                if ( right ) args.push_back( new VariableExpr( right ) );
     211                return new UntypedExpr( new NameExpr( fname ), args );
    174212        }
    175213
     
    182220                static UniqueName lhsNamer( "__massassign_L" );
    183221                static UniqueName rhsNamer( "__massassign_R" );
    184                 assert ( ! lhs.empty() && rhs.size() == 1);
    185 
    186                 ObjectDecl * rtmp = newObject( rhsNamer, rhs.front().expr );
     222                assert ( ! lhs.empty() && rhs.size() <= 1);
     223
     224                ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;
    187225                for ( ResolvExpr::Alternative & lhsAlt : lhs ) {
    188                         ObjectDecl * ltmp = newObject( lhsNamer, new AddressExpr( lhsAlt.expr ) );
    189                         out.push_back( createAssgn( ltmp, rtmp ) );
     226                        ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr );
     227                        out.push_back( createFunc( spotter.fname, ltmp, rtmp ) );
    190228                        tmpDecls.push_back( ltmp );
    191229                }
    192                 tmpDecls.push_back( rtmp );
     230                if ( rtmp ) tmpDecls.push_back( rtmp );
    193231        }
    194232
     
    201239                        std::list< ObjectDecl * > rtmp;
    202240                        std::transform( lhs.begin(), lhs.end(), back_inserter( ltmp ), []( ResolvExpr::Alternative & alt ){
    203                                 return newObject( lhsNamer, new AddressExpr( alt.expr ) );
     241                                return newObject( lhsNamer, alt.expr );
    204242                        });
    205243                        std::transform( rhs.begin(), rhs.end(), back_inserter( rtmp ), []( ResolvExpr::Alternative & alt ){
    206244                                return newObject( rhsNamer, alt.expr );
    207245                        });
    208                         zipWith( ltmp.begin(), ltmp.end(), rtmp.begin(), rtmp.end(), back_inserter(out), createAssgn );
     246                        zipWith( ltmp.begin(), ltmp.end(), rtmp.begin(), rtmp.end(), back_inserter(out), [&](ObjectDecl * obj1, ObjectDecl * obj2 ) { return createFunc(spotter.fname, obj1, obj2); } );
    209247                        tmpDecls.splice( tmpDecls.end(), ltmp );
    210248                        tmpDecls.splice( tmpDecls.end(), rtmp );
Note: See TracChangeset for help on using the changeset viewer.