bool cxxParserParseBlockHandleOpeningBracket(void) { CXX_DEBUG_ENTER(); CXX_DEBUG_ASSERT( g_cxx.pToken->eType == CXXTokenTypeOpeningBracket, "This must be called when pointing at an opening bracket!" ); enum CXXScopeType eScopeType = cxxScopeGetType(); bool bIsCPP = cxxParserCurrentLanguageIsCPP(); CXXToken * pAux; if( ( // something = {...} (g_cxx.pToken->pPrev) && cxxTokenTypeIs(g_cxx.pToken->pPrev,CXXTokenTypeAssignment) && ( (eScopeType == CXXScopeTypeFunction) || (eScopeType == CXXScopeTypeNamespace) ) ) || ( bIsCPP && (g_cxx.pToken->pPrev) && ( ( // T { arg1, arg2, ... } (1) // T object { arg1, arg2, ... } (2) // new T { arg1, arg2, ... } (3) // Class::Class() : member { arg1, arg2, ... } { (4) cxxTokenTypeIs(g_cxx.pToken->pPrev,CXXTokenTypeIdentifier) && ( (!g_cxx.pToken->pPrev->pPrev) || (cxxTokenTypeIsOneOf( g_cxx.pToken->pPrev->pPrev, CXXTokenTypeIdentifier | CXXTokenTypeStar | CXXTokenTypeAnd | CXXTokenTypeGreaterThanSign | CXXTokenTypeKeyword | // FIXME: This check could be made stricter? CXXTokenTypeSingleColon | CXXTokenTypeComma )) ) && // "override" is handled as identifier since it's a keyword only after function signatures (strcmp(vStringValue(g_cxx.pToken->pPrev->pszWord),"override") != 0) ) || ( // type var[][][]..[] { ... } // (but not '[] { ... }' which is a parameterless lambda) cxxTokenTypeIs(g_cxx.pToken->pPrev,CXXTokenTypeSquareParenthesisChain) && ( pAux = cxxTokenChainPreviousTokenNotOfType( g_cxx.pToken->pPrev, CXXTokenTypeSquareParenthesisChain ) ) && cxxTokenTypeIs(pAux,CXXTokenTypeIdentifier) ) ) ) || ( // return { } (!g_cxx.pToken->pPrev) && (g_cxx.uKeywordState & CXXParserKeywordStateSeenReturn) ) ) { // array or list-like initialisation bool bRet = cxxParserParseAndCondenseCurrentSubchain( CXXTokenTypeOpeningBracket | CXXTokenTypeOpeningParenthesis | CXXTokenTypeOpeningSquareParenthesis, false, true ); CXX_DEBUG_LEAVE_TEXT("Handled array or list-like initialisation or return"); return bRet; } int iScopes; // FIXME: Why the invalid cork queue entry index is CORK_NIL? int iCorkQueueIndex = CORK_NIL; if(eScopeType != CXXScopeTypeFunction) { // very likely a function definition iScopes = cxxParserExtractFunctionSignatureBeforeOpeningBracket(&iCorkQueueIndex); // FIXME: Handle syntax (5) of list initialization: // Class::Class() : member { arg1, arg2, ... } {... } else { // some kind of other block: // - anonymous block // - block after for(),while(),foreach(),if() and other similar stuff // - lambda // check for lambdas CXXToken * pParenthesis; if( bIsCPP && (pParenthesis = cxxParserOpeningBracketIsLambda()) ) { CXX_DEBUG_LEAVE_TEXT("Will handle lambda"); return cxxParserHandleLambda(pParenthesis); } iScopes = 0; } cxxParserNewStatement(); if(!cxxParserParseBlock(true)) { CXX_DEBUG_LEAVE_TEXT("Failed to parse nested block"); return false; } if(iCorkQueueIndex > CORK_NIL) cxxParserMarkEndLineForTagInCorkQueue(iCorkQueueIndex); while(iScopes > 0) { cxxScopePop(); iScopes--; } CXX_DEBUG_LEAVE(); return true; }
bool cxxParserParseBlockHandleOpeningBracket(void) { CXX_DEBUG_ENTER(); CXX_DEBUG_ASSERT( g_cxx.pToken->eType == CXXTokenTypeOpeningBracket, "This must be called when pointing at an opening bracket!" ); enum CXXScopeType eScopeType = cxxScopeGetType(); bool bIsCPP = cxxParserCurrentLanguageIsCPP(); CXXToken * pAux; if( ( // something = {...} (g_cxx.pToken->pPrev) && cxxTokenTypeIs(g_cxx.pToken->pPrev,CXXTokenTypeAssignment) && ( (eScopeType == CXXScopeTypeFunction) || (eScopeType == CXXScopeTypeNamespace) ) ) || ( bIsCPP && (g_cxx.pToken->pPrev) && ( ( // T { arg1, arg2, ... } (1) // T object { arg1, arg2, ... } (2) // new T { arg1, arg2, ... } (3) // Class::Class() : member { arg1, arg2, ... } { (4) cxxTokenTypeIs(g_cxx.pToken->pPrev,CXXTokenTypeIdentifier) && ( // case 1 (!g_cxx.pToken->pPrev->pPrev) || // case 4 cxxTokenTypeIsOneOf( g_cxx.pToken->pPrev->pPrev, CXXTokenTypeSingleColon | CXXTokenTypeComma ) || // cases 1,2,3 but not 4 ( // more parts of typename or maybe the "new" keyword before the identifier cxxTokenTypeIsOneOf( g_cxx.pToken->pPrev->pPrev, CXXTokenTypeIdentifier | CXXTokenTypeStar | CXXTokenTypeAnd | CXXTokenTypeGreaterThanSign | CXXTokenTypeKeyword ) && // but no parenthesis (discard things like bool test() Q_DECL_NO_THROW { ... }) (!(pAux = cxxTokenChainPreviousTokenOfType( g_cxx.pToken->pPrev->pPrev, CXXTokenTypeParenthesisChain )) ) ) ) && // "override" is handled as identifier since it's a keyword only after function signatures (strcmp(vStringValue(g_cxx.pToken->pPrev->pszWord),"override") != 0) ) || ( // type var[][][]..[] { ... } // (but not '[] { ... }' which is a parameterless lambda) cxxTokenTypeIs(g_cxx.pToken->pPrev,CXXTokenTypeSquareParenthesisChain) && ( pAux = cxxTokenChainPreviousTokenNotOfType( g_cxx.pToken->pPrev, CXXTokenTypeSquareParenthesisChain ) ) && cxxTokenTypeIs(pAux,CXXTokenTypeIdentifier) ) ) ) || ( // return { } (!g_cxx.pToken->pPrev) && (g_cxx.uKeywordState & CXXParserKeywordStateSeenReturn) ) ) { // array or list-like initialisation bool bRet = cxxParserParseAndCondenseCurrentSubchain( CXXTokenTypeOpeningBracket | CXXTokenTypeOpeningParenthesis | CXXTokenTypeOpeningSquareParenthesis, false, true ); CXX_DEBUG_LEAVE_TEXT("Handled array or list-like initialisation or return"); return bRet; } // In C++ mode check for lambdas CXXToken * pParenthesis; if( bIsCPP && (pParenthesis = cxxParserOpeningBracketIsLambda()) ) { if(!cxxParserHandleLambda(pParenthesis)) { CXX_DEBUG_LEAVE_TEXT("Lambda handling failed"); return false; } // Note that here we're leaving the token chain "alive" so further parsing can be performed. CXX_DEBUG_LEAVE_TEXT("Lambda handling succeeded"); return true; } int iScopes; int iCorkQueueIndex = CORK_NIL; CXXFunctionSignatureInfo oInfo; if(eScopeType != CXXScopeTypeFunction) { // very likely a function definition // (but may be also a toplevel block, like "extern "C" { ... }") iScopes = cxxParserExtractFunctionSignatureBeforeOpeningBracket(&oInfo,&iCorkQueueIndex); // FIXME: Handle syntax (5) of list initialization: // Class::Class() : member { arg1, arg2, ... } {... } else { // some kind of other block: // - anonymous block // - block after for(),while(),foreach(),if() and other similar stuff // (note that {}-style initializers have been handled above and thus are excluded) iScopes = 0; } cxxParserNewStatement(); if(!cxxParserParseBlock(true)) { CXX_DEBUG_LEAVE_TEXT("Failed to parse nested block"); return false; } if(iScopes < 1) { CXX_DEBUG_LEAVE_TEXT("The block was not a function"); return true; } unsigned long uEndPosition = getInputLineNumber(); // If the function contained a "try" keyword before the opening bracket // then it's likely to be a function-try-block and should be followed by a catch // block that is in the same scope. if(oInfo.uFlags & CXXFunctionSignatureInfoFunctionTryBlock) { // look for the catch blocks. CXX_DEBUG_PRINT("The function is a function-try-block: looking for catch blocks"); for(;;) { CXX_DEBUG_PRINT("Looking ahead for a catch block..."); if(!cxxParserParseNextToken()) break; // EOF if(!cxxTokenIsKeyword(g_cxx.pToken,CXXKeywordCATCH)) { // No more catches. Unget and exit. CXX_DEBUG_PRINT("No more catch blocks"); cxxParserUngetCurrentToken(); break; } // assume it's a catch block. CXX_DEBUG_PRINT("Found catch block"); if(!cxxParserParseIfForWhileSwitchCatchParenthesis()) { CXX_DEBUG_LEAVE_TEXT("Failed to parse the catch parenthesis"); return false; } // the standard requires a bracket here (catch block is always a compound statement). cxxParserNewStatement(); if(!cxxParserParseNextToken()) { CXX_DEBUG_LEAVE_TEXT("Found EOF while looking for catch() block: playing nice"); break; // EOF (would be a syntax error!) } if(!cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeOpeningBracket)) { // Aargh... CXX_DEBUG_LEAVE_TEXT("Found something unexpected while looking for catch() block: playing nice"); cxxParserUngetCurrentToken(); break; // (would be a syntax error!) } if(!cxxParserParseBlock(true)) return false; uEndPosition = getInputLineNumber(); } } if(iCorkQueueIndex > CORK_NIL) cxxParserSetEndLineForTagInCorkQueue(iCorkQueueIndex,uEndPosition); while(iScopes > 0) { cxxScopePop(); iScopes--; } CXX_DEBUG_LEAVE(); return true; }
// // This function parses input until one of the specified // tokens appears. The algorithm will also build subchains of matching // pairs ([...],(...),<...>,{...}): within the subchain analysis // of uTokenTypes is completly disabled. Subchains do nest. // // Returns true if it stops before EOF or it stops at EOF and CXXTokenTypeEOF // is present in uTokenTypes. Returns false in all the other stop conditions // and when an unmatched subchain character pair is found (syntax error). // boolean cxxParserParseAndCondenseSubchainsUpToOneOf( unsigned int uTokenTypes, unsigned int uInitialSubchainMarkerTypes ) { CXX_DEBUG_ENTER_TEXT("Token types = 0x%x",uTokenTypes); if(!cxxParserParseNextToken()) { CXX_DEBUG_LEAVE_TEXT("Found EOF"); return (uTokenTypes & CXXTokenTypeEOF); // was already at EOF } // see the declaration of CXXTokenType enum. // Shifting by 4 gives the corresponding closing token type unsigned int uFinalSubchainMarkerTypes = uInitialSubchainMarkerTypes << 4; for(;;) { //CXX_DEBUG_PRINT( // "Current token is '%s' 0x%x", // vStringValue(g_cxx.pToken->pszWord), // g_cxx.pToken->eType //); if(cxxTokenTypeIsOneOf(g_cxx.pToken,uTokenTypes)) { CXX_DEBUG_LEAVE_TEXT( "Got terminator token '%s' 0x%x", vStringValue(g_cxx.pToken->pszWord), g_cxx.pToken->eType ); return TRUE; } if(cxxTokenTypeIsOneOf(g_cxx.pToken,uInitialSubchainMarkerTypes)) { // subchain CXX_DEBUG_PRINT( "Got subchain start token '%s' 0x%x", vStringValue(g_cxx.pToken->pszWord), g_cxx.pToken->eType ); CXXToken * pParenthesis; if( cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeOpeningBracket) && cxxParserCurrentLanguageIsCPP() && (pParenthesis = cxxParserOpeningBracketIsLambda()) ) { if(!cxxParserHandleLambda(pParenthesis)) { CXX_DEBUG_LEAVE_TEXT("Failed to handle lambda"); return FALSE; } } else { if(!cxxParserParseAndCondenseCurrentSubchain( uInitialSubchainMarkerTypes, (uTokenTypes & CXXTokenTypeEOF) ) ) { CXX_DEBUG_LEAVE_TEXT( "Failed to parse subchain of type 0x%x", g_cxx.pToken->eType ); return FALSE; } } if(cxxTokenTypeIsOneOf(g_cxx.pToken,uTokenTypes)) { // was looking for a subchain CXX_DEBUG_LEAVE_TEXT( "Got terminator subchain token 0x%x", g_cxx.pToken->eType ); return TRUE; } if(!cxxParserParseNextToken()) { CXX_DEBUG_LEAVE_TEXT("Found EOF(2)"); return (uTokenTypes & CXXTokenTypeEOF); // was already at EOF } continue; // jump up to avoid checking for mismatched pairs below } // Check for mismatched brackets/parenthis // Note that if we were looking for one of [({ then we would have matched // it at the top of the for if(cxxTokenTypeIsOneOf(g_cxx.pToken,uFinalSubchainMarkerTypes)) { CXX_DEBUG_LEAVE_TEXT( "Got mismatched subchain terminator 0x%x", g_cxx.pToken->eType ); return FALSE; // unmatched: syntax error } if(!cxxParserParseNextToken()) { CXX_DEBUG_LEAVE_TEXT("Found EOF(3)"); return (uTokenTypes & CXXTokenTypeEOF); // was already at EOF } } // not reached CXX_DEBUG_LEAVE_TEXT("Internal error"); return FALSE; }
static boolean cxxParserParseBlockHandleOpeningBracket(void) { CXX_DEBUG_ENTER(); CXX_DEBUG_ASSERT(g_cxx.pToken->eType == CXXTokenTypeOpeningBracket,"This must be called when pointing at an opening bracket!"); enum CXXTagKind eScopeKind = cxxScopeGetKind(); if( (g_cxx.pToken->pPrev) && cxxTokenTypeIs(g_cxx.pToken->pPrev,CXXTokenTypeAssignment) && ( (eScopeKind == CXXTagKindFUNCTION) || (eScopeKind == CXXTagKindNAMESPACE) ) ) { // array or C++11-list-like initialisation boolean bRet = cxxParserParseAndCondenseCurrentSubchain( CXXTokenTypeOpeningBracket | CXXTokenTypeOpeningParenthesis | CXXTokenTypeOpeningSquareParenthesis, FALSE ); CXX_DEBUG_LEAVE_TEXT("Handled array or C++11-list-like initialisation"); return bRet; } int iScopes; if(eScopeKind != CXXTagKindFUNCTION) { // very likely a function definition iScopes = cxxParserExtractFunctionSignatureBeforeOpeningBracket(); } else { // some kind of other block: // - anonymous block // - block after for(),while(),foreach(),if() and other similar stuff // - lambda // check for lambdas CXXToken * pParenthesis; if( cxxParserCurrentLanguageIsCPP() && (pParenthesis = cxxParserOpeningBracketIsLambda()) ) { CXX_DEBUG_LEAVE_TEXT("Will handle lambda"); return cxxParserHandleLambda(pParenthesis); } iScopes = 0; } cxxParserNewStatement(); if(!cxxParserParseBlock(TRUE)) { CXX_DEBUG_LEAVE_TEXT("Failed to parse nested block"); return FALSE; } while(iScopes > 0) { cxxScopePop(); iScopes--; } CXX_DEBUG_LEAVE(); return TRUE; }