Ignore:
Timestamp:
Aug 16, 2016, 3:20:06 PM (9 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, ctor, deferred_resn, demangler, enum, forall-pointer-decay, 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:
1f6d4624
Parents:
950f7a7 (diff), 7880579 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Parser/StatementNode.cc

    r950f7a7 r7527e63  
    1010// Created On       : Sat May 16 14:59:41 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Jul 12 17:21:02 2016
    13 // Update Count     : 133
     12// Last Modified On : Mon Aug 15 20:47:11 2016
     13// Update Count     : 322
    1414//
    1515
     
    2626using namespace std;
    2727
    28 const char *StatementNode::StType[] = {
    29         "Exp",   "If",       "Switch", "Case",    "Default",  "Choose",   "Fallthru",
    30         "While", "Do",       "For",
    31         "Goto",  "Continue", "Break",  "Return",  "Throw",
    32         "Try",   "Catch",    "Finally", "Asm",
    33         "Decl"
    34 };
    3528
    36 StatementNode::StatementNode() : ParseNode(), control( 0 ), block( 0 ), labels( 0 ), target( 0 ), decl( 0 ), isCatchRest ( false ) {}
    37 
    38 StatementNode::StatementNode( const string *name ) : ParseNode( name ), control( 0 ), block( 0 ), labels( 0 ), target( 0 ), decl( 0 ), isCatchRest ( false ) {}
    39 
    40 StatementNode::StatementNode( DeclarationNode *decl ) : type( Decl ), control( 0 ), block( 0 ), labels( 0 ), target( 0 ), isCatchRest ( false ) {
     29StatementNode::StatementNode( DeclarationNode *decl ) {
    4130        if ( decl ) {
    42                 if ( DeclarationNode *agg = decl->extractAggregate() ) {
    43                         this->decl = agg;
    44                         StatementNode *nextStmt = new StatementNode;
    45                         nextStmt->type = Decl;
    46                         nextStmt->decl = decl;
    47                         next = nextStmt;
    48                         if ( decl->get_link() ) {
    49                                 next->set_next( new StatementNode( dynamic_cast< DeclarationNode* >( decl->get_link() ) ) );
     31                DeclarationNode *agg = decl->extractAggregate();
     32                if ( agg ) {
     33                        StatementNode *nextStmt = new StatementNode( new DeclStmt( noLabels, maybeBuild< Declaration >( decl ) ) );
     34                        set_next( nextStmt );
     35                        if ( decl->get_next() ) {
     36                                get_next()->set_next( new StatementNode( dynamic_cast< DeclarationNode * >(decl->get_next()) ) );
    5037                                decl->set_next( 0 );
    5138                        } // if
    5239                } else {
    53                         if ( decl->get_link() ) {
    54                                 next = new StatementNode( dynamic_cast< DeclarationNode* >( decl->get_link() ) );
     40                        if ( decl->get_next() ) {
     41                                set_next(new StatementNode( dynamic_cast< DeclarationNode * >( decl->get_next() ) ) );
    5542                                decl->set_next( 0 );
    5643                        } // if
    57                         this->decl = decl;
     44                        agg = decl;
    5845                } // if
     46                stmt = new DeclStmt( noLabels, maybeBuild< Declaration >(agg) );
     47        } else {
     48                assert( false );
    5949        } // if
    6050}
    6151
    62 StatementNode::StatementNode( Type t, ExpressionNode *ctrl_label, StatementNode *block ) : type( t ), control( ctrl_label ), block( block ), labels( 0 ), target( 0 ), decl( 0 ), isCatchRest ( false ) {
    63         this->control = ( t == Default ) ? 0 : control;
    64 }
    65 
    66 StatementNode::StatementNode( Type t, string *target ) : type( t ), control( 0 ), block( 0 ), labels( 0 ), target( target ), decl( 0 ), isCatchRest ( false ) {}
    67 
    68 StatementNode::~StatementNode() {
    69         delete control;
    70         delete block;
    71         delete target;
    72         delete decl;
    73 }
    74 
    75 StatementNode * StatementNode::newCatchStmt( DeclarationNode *d, StatementNode *s, bool catchRestP ) {
    76         StatementNode *ret = new StatementNode( StatementNode::Catch, 0, s );
    77         ret->addDeclaration( d );
    78         ret->setCatchRest( catchRestP );
    79 
    80         return ret;
    81 }
    82 
    83 std::string StatementNode::get_target() const{
    84         if ( target )
    85                 return *target;
    86 
    87         return string("");
    88 }
    89 
    90 StatementNode * StatementNode::clone() const {
    91         StatementNode *newnode = new StatementNode( type, maybeClone( control ), maybeClone( block ) );
    92         if ( target ) {
    93                 newnode->target = new string( *target );
    94         } else {
    95                 newnode->target = 0;
    96         } // if
    97         newnode->decl = maybeClone( decl );
    98         return newnode;
    99 }
    100 
    101 StatementNode *StatementNode::add_label( const std::string *l ) {
    102         if ( l != 0 ) {
    103                 labels.push_front( *l );
    104                 delete l;
    105         } // if
     52StatementNode *StatementNode::append_last_case( StatementNode *stmt ) {
     53        StatementNode *prev = this;
     54        // find end of list and maintain previous pointer
     55        for ( StatementNode * curr = prev; curr != nullptr; curr = (StatementNode *)curr->get_next() ) {
     56                StatementNode *node = dynamic_cast< StatementNode * >(curr);
     57                assert( node );
     58                assert( dynamic_cast< CaseStmt * >(node->stmt) );
     59                prev = curr;
     60        } // for
     61        // convert from StatementNode list to Statement list
     62        StatementNode *node = dynamic_cast< StatementNode * >(prev);
     63        std::list< Statement * > stmts;
     64        buildList( stmt, stmts );
     65        // splice any new Statements to end of current Statements
     66        CaseStmt * caseStmt = dynamic_cast< CaseStmt * >(node->stmt);
     67        caseStmt->get_statements().splice( caseStmt->get_statements().end(), stmts );
    10668        return this;
    10769}
    10870
    109 StatementNode *StatementNode::add_controlexp( ExpressionNode *e ) {
    110         if ( control && e )
    111                 control->add_to_list( e ); // xxx - check this
    112         return this;
     71Statement *build_expr( ExpressionNode *ctl ) {
     72        Expression *e = maybeBuild< Expression >( ctl );
     73
     74        if ( e )
     75                return new ExprStmt( noLabels, e );
     76        else
     77                return new NullStmt( noLabels );
    11378}
    11479
    115 StatementNode *StatementNode::append_block( StatementNode *stmt ) {
    116         if ( stmt != 0 ) {
    117                 if ( block == 0 )
    118                         block = stmt;
    119                 else
    120                         block->set_link( stmt );
     80Statement *build_if( ExpressionNode *ctl, StatementNode *then_stmt, StatementNode *else_stmt ) {
     81        Statement *thenb, *elseb = 0;
     82        std::list< Statement * > branches;
     83        buildList< Statement, StatementNode >( then_stmt, branches );
     84        assert( branches.size() == 1 );
     85        thenb = branches.front();
     86
     87        if ( else_stmt ) {
     88                std::list< Statement * > branches;
     89                buildList< Statement, StatementNode >( else_stmt, branches );
     90                assert( branches.size() == 1 );
     91                elseb = branches.front();
    12192        } // if
    122         return this;
     93        return new IfStmt( noLabels, notZeroExpr( maybeBuild< Expression >(ctl) ), thenb, elseb );
    12394}
    12495
    125 StatementNode *StatementNode::append_last_case( StatementNode *stmt ) {
    126         if ( stmt != 0 ) {
    127                 StatementNode *next = ( StatementNode *)get_link();
    128                 if ( next && ( next->get_type() == StatementNode::Case || next->get_type() == StatementNode::Default ) )
    129                         next->append_last_case ( stmt );
    130                 else
    131                         if ( block == 0 )
    132                                 block = stmt;
    133                         else
    134                                 block->set_link( stmt );
    135         } // if
    136         return this;
     96Statement *build_switch( ExpressionNode *ctl, StatementNode *stmt ) {
     97        std::list< Statement * > branches;
     98        buildList< Statement, StatementNode >( stmt, branches );
     99        assert( branches.size() >= 0 );                                         // size == 0 for switch (...) {}, i.e., no declaration or statements
     100        return new SwitchStmt( noLabels, maybeBuild< Expression >(ctl), branches );
     101}
     102Statement *build_case( ExpressionNode *ctl ) {
     103        std::list< Statement * > branches;
     104        return new CaseStmt( noLabels, maybeBuild< Expression >(ctl), branches );
     105}
     106Statement *build_default() {
     107        std::list< Statement * > branches;
     108        return new CaseStmt( noLabels, nullptr, branches, true );
    137109}
    138110
    139 void StatementNode::print( std::ostream &os, int indent ) const {
    140         if ( ! labels.empty() ) {
    141                 std::list<std::string>::const_iterator i;
     111Statement *build_while( ExpressionNode *ctl, StatementNode *stmt, bool kind ) {
     112        std::list< Statement * > branches;
     113        buildList< Statement, StatementNode >( stmt, branches );
     114        assert( branches.size() == 1 );
     115        return new WhileStmt( noLabels, notZeroExpr( maybeBuild< Expression >(ctl) ), branches.front(), kind );
     116}
    142117
    143                 os << string( indent, ' ' );
    144                 for ( i = labels.begin(); i != labels.end(); i++ )
    145                         os << *i << ":";
    146                 os << endl;
     118Statement *build_for( ForCtl *forctl, StatementNode *stmt ) {
     119        std::list< Statement * > branches;
     120        buildList< Statement, StatementNode >( stmt, branches );
     121        assert( branches.size() == 1 );
     122
     123        std::list< Statement * > init;
     124        if ( forctl->init != 0 ) {
     125                buildList( forctl->init, init );
    147126        } // if
    148127
    149         switch ( type ) {
    150           case Decl:
    151                 decl->print( os, indent );
    152                 break;
    153           case Exp:
    154                 if ( control ) {
    155                         os << string( indent, ' ' );
    156                         control->print( os, indent );
    157                         os << endl;
    158                 } else
    159                         os << string( indent, ' ' ) << "Null Statement" << endl;
    160                 break;
    161           default:
    162                 os << string( indent, ' ' ) << StatementNode::StType[type] << endl;
    163                 if ( type == Catch ) {
    164                         if ( decl ) {
    165                                 os << string( indent + ParseNode::indent_by, ' ' ) << "Declaration: " << endl;
    166                                 decl->print( os, indent + 2 * ParseNode::indent_by );
    167                         } else if ( isCatchRest ) {
    168                                 os << string( indent + ParseNode::indent_by, ' ' ) << "Catches the rest " << endl;
    169                         } else {
    170                                 ; // should never reach here
    171                         } // if
    172                 } // if
    173                 if ( control ) {
    174                         os << string( indent + ParseNode::indent_by, ' ' ) << "Control: " << endl;
    175                         control->printList( os, indent + 2 * ParseNode::indent_by );
    176                 } // if
    177                 if ( block ) {
    178                         os << string( indent + ParseNode::indent_by, ' ' ) << "Branches of execution: " << endl;
    179                         block->printList( os, indent + 2 * ParseNode::indent_by );
    180                 } // if
    181                 if ( target ) {
    182                         os << string( indent + ParseNode::indent_by, ' ' ) << "Target: " << get_target() << endl;
    183                 } // if
    184                 break;
    185         } // switch
     128        Expression *cond = 0;
     129        if ( forctl->condition != 0 )
     130                cond = notZeroExpr( maybeBuild< Expression >(forctl->condition) );
     131
     132        Expression *incr = 0;
     133        if ( forctl->change != 0 )
     134                incr = maybeBuild< Expression >(forctl->change);
     135
     136        delete forctl;
     137        return new ForStmt( noLabels, init, cond, incr, branches.front() );
    186138}
    187139
    188 Statement *StatementNode::build() const {
    189         std::list<Statement *> branches;
    190         std::list<Expression *> exps;
    191         std::list<Label> labs;
    192 
    193         if ( ! labels.empty() ) {
    194                 std::back_insert_iterator< std::list<Label> > lab_it( labs );
    195                 copy( labels.begin(), labels.end(), lab_it );
    196         } // if
    197 
    198         // try {
    199         buildList<Statement, StatementNode>( get_block(), branches );
    200 
    201         switch ( type ) {
    202           case Decl:
    203                 return new DeclStmt( labs, maybeBuild< Declaration >( decl ) );
    204           case Exp:
    205                 {
    206                         Expression *e = maybeBuild< Expression >( get_control() );
    207 
    208                         if ( e )
    209                                 return new ExprStmt( labs, e );
    210                         else
    211                                 return new NullStmt( labs );
    212                 }
    213           case If:
    214                 {
    215                         Statement *thenb = 0, *elseb = 0;
    216                         assert( branches.size() >= 1 );
    217 
    218                         thenb = branches.front();
    219                         branches.pop_front();
    220                         if ( ! branches.empty() ) {
    221                                 elseb = branches.front();
    222                                 branches.pop_front();
    223                         } // if
    224                         return new IfStmt( labs, notZeroExpr( maybeBuild<Expression>(get_control()) ), thenb, elseb );
    225                 }
    226           case While:
    227                 assert( branches.size() == 1 );
    228                 return new WhileStmt( labs, notZeroExpr( maybeBuild<Expression>(get_control()) ), branches.front() );
    229           case Do:
    230                 assert( branches.size() == 1 );
    231                 return new WhileStmt( labs, notZeroExpr( maybeBuild<Expression>(get_control()) ), branches.front(), true );
    232           case For:
    233                 {
    234                         assert( branches.size() == 1 );
    235 
    236                         ForCtlExprNode *ctl = dynamic_cast<ForCtlExprNode *>( get_control() );
    237                         assert( ctl != 0 );
    238 
    239                         std::list<Statement *> init;
    240                         if ( ctl->get_init() != 0 ) {
    241                                 buildList( ctl->get_init(), init );
    242                         } // if
    243 
    244                         Expression *cond = 0;
    245                         if ( ctl->get_condition() != 0 )
    246                                 cond = notZeroExpr( maybeBuild<Expression>(ctl->get_condition()) );
    247 
    248                         Expression *incr = 0;
    249                         if ( ctl->get_change() != 0 )
    250                                 incr = maybeBuild<Expression>(ctl->get_change());
    251 
    252                         return new ForStmt( labs, init, cond, incr, branches.front() );
    253                 }
    254           case Switch:
    255                 return new SwitchStmt( labs, maybeBuild<Expression>(get_control()), branches );
    256           case Case:
    257                 return new CaseStmt( labs, maybeBuild<Expression>(get_control()), branches );
    258           case Default:
    259                 return new CaseStmt( labs, 0, branches, true );
    260           case Goto:
    261                 {
    262                         if ( get_target() == "" ) {                                     // computed goto
    263                                 assert( get_control() != 0 );
    264                                 return new BranchStmt( labs, maybeBuild<Expression>(get_control()), BranchStmt::Goto );
    265                         } // if
    266 
    267                         return new BranchStmt( labs, get_target(), BranchStmt::Goto );
    268                 }
    269           case Break:
    270                 return new BranchStmt( labs, get_target(), BranchStmt::Break );
    271           case Continue:
    272                 return new BranchStmt( labs, get_target(), BranchStmt::Continue );
    273           case Return:
    274           case Throw :
    275                 buildList( get_control(), exps );
    276                 if ( exps.size() ==0 )
    277                         return new ReturnStmt( labs, 0, type == Throw );
    278                 if ( exps.size() > 0 )
    279                         return new ReturnStmt( labs, exps.back(), type == Throw );
    280           case Try:
    281                 {
    282                         assert( branches.size() >= 0 );
    283                         CompoundStmt *tryBlock = dynamic_cast<CompoundStmt *>( branches.front());
    284                         branches.pop_front();
    285                         FinallyStmt *finallyBlock = 0;
    286                         if ( ( finallyBlock = dynamic_cast<FinallyStmt *>( branches.back())) ) {
    287                                 branches.pop_back();
    288                         } // if
    289                         return new TryStmt( labs, tryBlock, branches, finallyBlock );
    290                 }
    291           case Catch:
    292                 {
    293                         assert( branches.size() == 1 );
    294 
    295                         return new CatchStmt( labs, maybeBuild< Declaration >( decl ), branches.front(), isCatchRest );
    296                 }
    297           case Finally:
    298                 {
    299                         assert( branches.size() == 1 );
    300                         CompoundStmt *block = dynamic_cast<CompoundStmt *>( branches.front() );
    301                         assert( block != 0 );
    302 
    303                         return new FinallyStmt( labs, block );
    304                 }
    305           case Asm:
    306                 assert( false );
    307           default:
    308                 // shouldn't be here
    309                 return 0;
    310         } // switch
     140Statement *build_branch( std::string identifier, BranchStmt::Type kind ) {
     141        return new BranchStmt( noLabels, identifier, kind );
     142}
     143Statement *build_computedgoto( ExpressionNode *ctl ) {
     144        return new BranchStmt( noLabels, maybeBuild< Expression >(ctl), BranchStmt::Goto );
    311145}
    312146
    313 
    314 CompoundStmtNode::CompoundStmtNode() : first( 0 ), last( 0 ) {}
    315 
    316 CompoundStmtNode::CompoundStmtNode( const string *name_ ) : StatementNode( name_ ), first( 0 ), last( 0 ) {}
    317 
    318 CompoundStmtNode::CompoundStmtNode( StatementNode *stmt ) : first( stmt ) {
    319         if ( first ) {
    320                 last = ( StatementNode *)( stmt->get_last());
    321         } else {
    322                 last = 0;
    323         } // if
     147Statement *build_return( ExpressionNode *ctl ) {
     148        std::list< Expression * > exps;
     149        buildList( ctl, exps );
     150        return new ReturnStmt( noLabels, exps.size() > 0 ? exps.back() : nullptr );
     151}
     152Statement *build_throw( ExpressionNode *ctl ) {
     153        std::list< Expression * > exps;
     154        buildList( ctl, exps );
     155        return new ReturnStmt( noLabels, exps.size() > 0 ? exps.back() : nullptr, true );
    324156}
    325157
    326 CompoundStmtNode::~CompoundStmtNode() {
    327         delete first;
     158Statement *build_try( StatementNode *try_stmt, StatementNode *catch_stmt, StatementNode *finally_stmt ) {
     159        std::list< Statement * > branches;
     160        buildList< Statement, StatementNode >( catch_stmt, branches );
     161        CompoundStmt *tryBlock = dynamic_cast< CompoundStmt * >(maybeBuild< Statement >(try_stmt));
     162        assert( tryBlock );
     163        FinallyStmt *finallyBlock = dynamic_cast< FinallyStmt * >(maybeBuild< Statement >(finally_stmt) );
     164        return new TryStmt( noLabels, tryBlock, branches, finallyBlock );
     165}
     166Statement *build_catch( DeclarationNode *decl, StatementNode *stmt, bool catchAny ) {
     167        std::list< Statement * > branches;
     168        buildList< Statement, StatementNode >( stmt, branches );
     169        assert( branches.size() == 1 );
     170        return new CatchStmt( noLabels, maybeBuild< Declaration >(decl), branches.front(), catchAny );
     171}
     172Statement *build_finally( StatementNode *stmt ) {
     173        std::list< Statement * > branches;
     174        buildList< Statement, StatementNode >( stmt, branches );
     175        assert( branches.size() == 1 );
     176        return new FinallyStmt( noLabels, dynamic_cast< CompoundStmt * >( branches.front() ) );
    328177}
    329178
    330 void CompoundStmtNode::add_statement( StatementNode *stmt ) {
    331         if ( stmt != 0 ) {
    332                 last->set_link( stmt );
    333                 last = ( StatementNode *)( stmt->get_link());
    334         } // if
    335 }
    336 
    337 void CompoundStmtNode::print( ostream &os, int indent ) const {
    338         if ( first ) {
    339                 first->printList( os, indent+2 );
    340         } // if
    341 }
    342 
    343 Statement *CompoundStmtNode::build() const {
    344         std::list<Label> labs;
    345         const std::list<std::string> &labels = get_labels();
    346 
    347         if ( ! labels.empty() ) {
    348                 std::back_insert_iterator< std::list<Label> > lab_it( labs );
    349                 copy( labels.begin(), labels.end(), lab_it );
    350         } // if
    351 
    352         CompoundStmt *cs = new CompoundStmt( labs );
     179Statement *build_compound( StatementNode *first ) {
     180        CompoundStmt *cs = new CompoundStmt( noLabels );
    353181        buildList( first, cs->get_kids() );
    354182        return cs;
    355183}
    356184
    357 
    358 AsmStmtNode::AsmStmtNode( Type t, bool voltile, ConstantNode *instruction, ExpressionNode *output, ExpressionNode *input, ConstantNode *clobber, LabelNode *gotolabels ) :
    359         StatementNode( t ), voltile( voltile ), instruction( instruction ), output( output ), input( input ), clobber( clobber ) {
    360         if ( gotolabels ) {
    361                 this->gotolabels = gotolabels->get_labels();
    362                 delete gotolabels;
    363         } // if
    364 }
    365 
    366 AsmStmtNode::~AsmStmtNode() {
    367         delete instruction; delete output; delete input; delete clobber;
    368 }
    369 
    370 void AsmStmtNode::print( std::ostream &os, int indent ) const {
    371         StatementNode::print( os, indent );                                     // print statement labels
    372         os << string( indent + ParseNode::indent_by, ' ' ) << "volatile:" << voltile << endl;
    373         if ( instruction ) {
    374                 os << string( indent + ParseNode::indent_by, ' ' ) << "Instruction:" << endl;
    375                 instruction->printList( os, indent + 2 * ParseNode::indent_by );
    376         } // if
    377         if ( output ) {
    378                 os << string( indent + ParseNode::indent_by, ' ' ) << "Output:" << endl;
    379                 output->printList( os, indent + 2 * ParseNode::indent_by );
    380         } // if
    381         if ( input ) {
    382                 os << string( indent + ParseNode::indent_by, ' ' ) << "Input:" << endl;
    383                 input->printList( os, indent + 2 * ParseNode::indent_by );
    384         } // if
    385         if ( clobber ) {
    386                 os << string( indent + ParseNode::indent_by, ' ' ) << "Clobber:" << endl;
    387                 clobber->printList( os, indent + 2 * ParseNode::indent_by );
    388         } // if
    389         if ( ! gotolabels.empty() ) {
    390                 os << string( indent + ParseNode::indent_by, ' ' ) << "Goto Labels:" << endl;
    391                 os << string( indent + 2 * ParseNode::indent_by, ' ' );
    392                 for ( std::list<Label>::const_iterator i = gotolabels.begin();; ) {
    393                         os << *i;
    394                         i++;
    395                   if ( i == gotolabels.end() ) break;
    396                         os << ", ";
    397                 }
    398                 os << endl;
    399         } // if
    400 }
    401 
    402 Statement *AsmStmtNode::build() const {
    403         std::list<Label> labs;
    404 
    405         if ( ! get_labels().empty() ) {
    406                 std::back_insert_iterator< std::list<Label> > lab_it( labs );
    407                 copy( get_labels().begin(), get_labels().end(), lab_it );
    408         } // if
    409 
     185Statement *build_asmstmt( bool voltile, ConstantExpr *instruction, ExpressionNode *output, ExpressionNode *input, ExpressionNode *clobber, LabelNode *gotolabels ) {
    410186        std::list< Expression * > out, in;
    411187        std::list< ConstantExpr * > clob;
     188
    412189        buildList( output, out );
    413190        buildList( input, in );
    414191        buildList( clobber, clob );
    415         std::list< Label > gotolabs = gotolabels;
    416         return new AsmStmt( labs, voltile, (ConstantExpr *)maybeBuild< Expression >( instruction ), out, in, clob, gotolabs );
    417 }
    418 
    419 
    420 void NullStmtNode::print( ostream &os, int indent ) const {
    421         os << string( indent, ' ' ) << "Null Statement:" << endl;
    422 }
    423 
    424 Statement *NullStmtNode::build() const {
    425         return new NullStmt;
     192        return new AsmStmt( noLabels, voltile, instruction, out, in, clob, gotolabels ? gotolabels->labels : noLabels );
    426193}
    427194
Note: See TracChangeset for help on using the changeset viewer.