diff --git a/NEWS.md b/NEWS.md index d1279b08..a083a397 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,8 +1,8 @@ Red Panda C++ Version 2.2 - - enhancement: basic code completion support for C++ lambda + - enhancement: basic code completion support for C++ lambdas - enhancement: slightly reduce parsing time - - fix: Wrong charset name returned when saveing file + - fix: Wrong charset name returned when saving file - fix: 'using =' / 'namespace =' not correctly handled - fix: Pressing '*' at begin of line will crash app diff --git a/RedPandaIDE/parser/cppparser.cpp b/RedPandaIDE/parser/cppparser.cpp index 1ba26040..8aa24efa 100644 --- a/RedPandaIDE/parser/cppparser.cpp +++ b/RedPandaIDE/parser/cppparser.cpp @@ -957,7 +957,6 @@ void CppParser::resetParser() mCurrentScope.clear(); mCurrentClassScope.clear(); - mSkipList.clear(); mStatementList.clear(); mProjectFiles.clear(); @@ -1460,15 +1459,19 @@ void CppParser::removeScopeLevel(int line) // qDebug()<<"--remove scope"<kind == StatementKind::skBlock)) { - if (currentScope->children.isEmpty()) { - // remove no children block - if (fileIncludes) { - fileIncludes->scopes.removeLastScope(); + if (currentScope) { + if (currentScope->kind == StatementKind::skBlock) { + if (currentScope->children.isEmpty()) { + // remove no children block + if (fileIncludes) { + fileIncludes->scopes.removeLastScope(); + } + mStatementList.deleteStatement(currentScope); + } else { + fileIncludes->statements.insert(currentScope->fullName,currentScope); } - mStatementList.deleteStatement(currentScope); - } else { - fileIncludes->statements.insert(currentScope->fullName,currentScope); + } else if (currentScope->kind == StatementKind::skClass) { + mIndex=indexOfNextSemicolon(mIndex); } } mCurrentScope.pop_back(); @@ -1494,7 +1497,6 @@ void CppParser::internalClear() mCurrentClassScope.clear(); mIndex = 0; mClassScope = StatementClassScope::None; - mSkipList.clear(); mBlockBeginSkips.clear(); mBlockEndSkips.clear(); mInlineNamespaceEndSkips.clear(); @@ -1729,14 +1731,6 @@ bool CppParser::checkForScope(KeywordType keywordType) ); } -void CppParser::checkForSkipStatement() -{ - if ((mSkipList.count()>0) && (mIndex == mSkipList.back())) { // skip to next ';' - skipNextSemicolon(mIndex); - mSkipList.pop_back(); - } -} - bool CppParser::checkForStructs(KeywordType keywordType) { int dis = 0; @@ -2181,7 +2175,7 @@ void CppParser::handleCatchBlock() true, false); addSoloScopeLevel(block,startLine); - scanMethodArgs(block,mIndex, mTokenizer[mIndex]->matchIndex); + scanMethodArgs(block,mIndex); mIndex=mTokenizer[mIndex]->matchIndex+1; } @@ -2450,8 +2444,9 @@ void CppParser::handleKeyword(KeywordType skipType) void CppParser::handleLambda(int index) { Q_ASSERT(mTokenizer[index]->text.startsWith('[')); + Q_ASSERT(mTokenizer[index+1]->text.startsWith('(')); int startLine=mTokenizer[index]->line; - int argStart=index; + int argStart=index+1; int argEnd= mTokenizer[argStart]->matchIndex; int blockLine=mTokenizer[argStart]->line; //TODO: parse captures @@ -2473,7 +2468,7 @@ void CppParser::handleLambda(int index) StatementClassScope::None, true, false); - scanMethodArgs(lambdaBlock,argStart,argEnd); + scanMethodArgs(lambdaBlock,argStart); addSoloScopeLevel(lambdaBlock,blockLine); } @@ -2536,7 +2531,6 @@ void CppParser::handleMethod(StatementKind functionKind,const QString &sType, co scopeStatement->friends.insert(scopelessName); } else if (isValid) { // Use the class the function belongs to as the parent ID if the function is declared outside of the class body - int delimPos = sName.lastIndexOf("::"); QString scopelessName; QString parentClassName; if (splitLastMember(sName,scopelessName,parentClassName)) { @@ -2563,7 +2557,7 @@ void CppParser::handleMethod(StatementKind functionKind,const QString &sType, co mClassScope, true, isStatic); - scanMethodArgs(functionStatement, argStart,argEnd); + scanMethodArgs(functionStatement, argStart); // add variable this to the class function if (scopeStatement && scopeStatement->kind == StatementKind::skClass && !isStatic) { @@ -3031,10 +3025,10 @@ bool CppParser::handleStatement() } Q_ASSERT(mIndex<999999); - while (mTokenizer.lambdasCount()>0 && mTokenizer.indexOfFirstLambda()0 && mTokenizer.indexOfFirstLambda()text.front() == ';' || mTokenizer[i + 1]->text.front() == '}')) { // When encountering names again after struct body scanning, skip it - mSkipList.append(i+1); // add first name to skip statement so that we can skip it until the next ; QString command = ""; QString args = ""; @@ -3599,7 +3592,7 @@ void CppParser::internalParse(const QString &fileName) QStringList preprocessResult = mPreprocessor.result(); #ifdef QT_DEBUG - stringsToFile(mPreprocessor.result(),QString("r:\\preprocess-%1.txt").arg(extractFileName(fileName))); +// stringsToFile(mPreprocessor.result(),QString("r:\\preprocess-%1.txt").arg(extractFileName(fileName))); // mPreprocessor.dumpDefinesTo("r:\\defines.txt"); // mPreprocessor.dumpIncludesListTo("r:\\includes.txt"); #endif @@ -3613,7 +3606,7 @@ void CppParser::internalParse(const QString &fileName) if (mTokenizer.tokenCount() == 0) return; #ifdef QT_DEBUG - mTokenizer.dumpTokens(QString("r:\\tokens-%1.txt").arg(extractFileName(fileName))); +// mTokenizer.dumpTokens(QString("r:\\tokens-%1.txt").arg(extractFileName(fileName))); #endif // Process the token list while(true) { @@ -3621,8 +3614,8 @@ void CppParser::internalParse(const QString &fileName) break; } #ifdef QT_DEBUG - mStatementList.dumpAll(QString("r:\\all-stats-%1.txt").arg(extractFileName(fileName))); - mStatementList.dump(QString("r:\\stats-%1.txt").arg(extractFileName(fileName))); +// mStatementList.dumpAll(QString("r:\\all-stats-%1.txt").arg(extractFileName(fileName))); +// mStatementList.dump(QString("r:\\stats-%1.txt").arg(extractFileName(fileName))); #endif //reduce memory usage internalClear(); @@ -4637,8 +4630,10 @@ int CppParser::calcKeyLenForStruct(const QString &word) return -1; } -void CppParser::scanMethodArgs(const PStatement& functionStatement, int argStart, int argEnd) +void CppParser::scanMethodArgs(const PStatement& functionStatement, int argStart) { + Q_ASSERT(mTokenizer[argStart]->text=='('); + int argEnd=mTokenizer[argStart]->matchIndex; int paramStart = argStart+1; int i = paramStart ; // assume it starts with ( and ends with ) // Keep going and stop on top of the variable name diff --git a/RedPandaIDE/parser/cppparser.h b/RedPandaIDE/parser/cppparser.h index 66156c9a..f834e584 100644 --- a/RedPandaIDE/parser/cppparser.h +++ b/RedPandaIDE/parser/cppparser.h @@ -216,7 +216,6 @@ private: bool checkForPreprocessor(); // bool checkForLambda(); bool checkForScope(KeywordType keywordType); - void checkForSkipStatement(); bool checkForStructs(KeywordType keywordType); bool checkForTypedefEnum(); bool checkForTypedefStruct(); @@ -451,8 +450,7 @@ private: // } void scanMethodArgs( const PStatement& functionStatement, - int argStart, - int argEnd); + int argStart); QString splitPhrase(const QString& phrase, QString& sClazz, QString& sOperator, QString &sMember); QString removeTemplateParams(const QString& phrase); @@ -608,9 +606,6 @@ private: QVector mCurrentScope; QVector mCurrentClassScope; -// the start index in tokens to skip to ; when parsing typedef struct we need to skip -// the names after the closing bracket because we have processed it - QVector mSkipList; // TList StatementClassScope mClassScope; StatementModel mStatementList; //It's used in preprocessor, so we can't use fIncludeList instead diff --git a/RedPandaIDE/parser/cpptokenizer.cpp b/RedPandaIDE/parser/cpptokenizer.cpp index 4ade57ee..30da8b35 100644 --- a/RedPandaIDE/parser/cpptokenizer.cpp +++ b/RedPandaIDE/parser/cpptokenizer.cpp @@ -113,7 +113,9 @@ void CppTokenizer::addToken(const QString &sText, int iLine, TokenType tokenType PToken token = std::make_shared(); token->text = sText; token->line = iLine; +#ifdef Q_DEBUG token->matchIndex = 1000000000; +#endif switch(tokenType) { case TokenType::LeftBrace: token->matchIndex=-1; @@ -573,16 +575,16 @@ void CppTokenizer::skipDoubleQuotes() } } -void CppTokenizer::skipPair(const QChar &cStart, const QChar cEnd, bool keepLambda) +void CppTokenizer::skipPair(const QChar &cStart, const QChar cEnd) { mCurrent++; while (*mCurrent != 0) { if (*mCurrent == '(') { - skipPair('(', ')',keepLambda); + skipPair('(', ')'); } else if (*mCurrent == '[') { - skipPair('[', ']',keepLambda); + skipPair('[', ']'); } else if (*mCurrent == '{') { - skipPair('{', '}',keepLambda); + skipPair('{', '}'); } else if (*mCurrent == cStart) { skipPair(cStart, cEnd); } else if (*mCurrent == cEnd) { @@ -603,8 +605,6 @@ void CppTokenizer::skipPair(const QChar &cStart, const QChar cEnd, bool keepLamb skipSingleQuote(); // don't do it inside AnsiString! else mCurrent++; - } else if (failChars.contains(*mCurrent)) { - break; } else { mCurrent++; } @@ -614,26 +614,40 @@ void CppTokenizer::skipPair(const QChar &cStart, const QChar cEnd, bool keepLamb bool CppTokenizer::skipAngleBracketPair() { QChar* backup=mCurrent; - int level=0; + QVector stack; while (*mCurrent != '\0') { switch((*mCurrent).unicode()) { case '<': case '(': case '[': - level++; + stack.push_back(*mCurrent); break; case ')': - case ']': - level--; - if (level==0) { + while (!stack.isEmpty() && stack.back()!='(') { + stack.pop_back(); + } + //pop up '(' + if (stack.isEmpty()) { mCurrent=backup; return false; } + stack.pop_back(); + break; + case ']': + while (!stack.isEmpty() && stack.back()!='[') + stack.pop_back(); + //pop up '[' + if (stack.isEmpty()) { + mCurrent=backup; + return false; + } + stack.pop_back(); break; case '>': - level--; - if (level==0) { - mCurrent++; //skip over > + if (stack.back()=='<') + stack.pop_back(); + if (stack.isEmpty()) { + mCurrent++; return true; } break; @@ -766,9 +780,11 @@ void CppTokenizer::removeFirstLambda() void CppTokenizer::advance() { switch(mCurrent->unicode()) { - case '\"': skipDoubleQuotes(); + case '\"': + skipDoubleQuotes(); break; - case '\'': skipSingleQuote(); + case '\'': + skipSingleQuote(); break; case '/': if (*(mCurrent + 1) == '=')