From ef79640eb0c2d466fa9fa5499bc45ec6b4c57e01 Mon Sep 17 00:00:00 2001 From: Roy Qu Date: Fri, 4 Nov 2022 23:44:11 +0800 Subject: [PATCH] work save --- RedPandaIDE/parser/cppparser.cpp | 131 ++++++++++++++++++++-------- RedPandaIDE/parser/cppparser.h | 5 +- RedPandaIDE/parser/cpptokenizer.cpp | 34 ++++++-- RedPandaIDE/parser/cpptokenizer.h | 13 ++- RedPandaIDE/parser/parserutils.cpp | 3 +- RedPandaIDE/parser/parserutils.h | 1 + 6 files changed, 137 insertions(+), 50 deletions(-) diff --git a/RedPandaIDE/parser/cppparser.cpp b/RedPandaIDE/parser/cppparser.cpp index 398d51a5..1ba26040 100644 --- a/RedPandaIDE/parser/cppparser.cpp +++ b/RedPandaIDE/parser/cppparser.cpp @@ -1447,7 +1447,8 @@ void CppParser::addSoloScopeLevel(PStatement& statement, int line, bool shouldRe else mClassScope = StatementClassScope::Public; // structs are public by default mCurrentClassScope.append(mClassScope); - qDebug()<<"++add scope"<kind == StatementKind::skBlock)) { @@ -1572,6 +1574,7 @@ bool CppParser::checkForKeyword(KeywordType& keywordType) case KeywordType::Protected: case KeywordType::None: case KeywordType::NotKeyword: + case KeywordType::DeclType: return false; default: return true; @@ -1815,15 +1818,23 @@ bool CppParser::checkForUsing(KeywordType keywordType) } -void CppParser::checkAndHandleMethodOrVar() +void CppParser::checkAndHandleMethodOrVar(KeywordType keywordType) { if (mIndex+2>=mTokenizer.tokenCount()) { mIndex+=2; // left's finish; return; } QString currentText=mTokenizer[mIndex]->text; - - mIndex++; + if (keywordType==KeywordType::DeclType) { + if (mTokenizer[mIndex+1]->text=='(') { + currentText="auto"; + mIndex=mTokenizer[mIndex+1]->matchIndex+1; + } else { + currentText=mTokenizer[mIndex+1]->text; + mIndex+=2; + } + } else + mIndex++; //next token must be */&/word/(/{ if (mTokenizer[mIndex]->text=='(') { int indexAfterParentheis=mTokenizer[mIndex]->matchIndex+1; @@ -1888,7 +1899,7 @@ void CppParser::checkAndHandleMethodOrVar() } // function call, skip it - skipNextSemicolon(mIndex); + moveToNextBraceOrSkipNextSemicolon(mIndex); } } else if (mTokenizer[mIndex]->text.startsWith('*') || mTokenizer[mIndex]->text.startsWith('&') @@ -2436,16 +2447,16 @@ void CppParser::handleKeyword(KeywordType skipType) } } -void CppParser::handleLambda() +void CppParser::handleLambda(int index) { - int startLine=mTokenizer[mIndex]->line; - int argStart=mIndex+1; + Q_ASSERT(mTokenizer[index]->text.startsWith('[')); + int startLine=mTokenizer[index]->line; + int argStart=index; int argEnd= mTokenizer[argStart]->matchIndex; int blockLine=mTokenizer[argStart]->line; //TODO: parse captures int bodyStart=indexOfNextLeftBrace(argEnd+1); if (bodyStart>=mTokenizer.tokenCount()) { - mIndex=argEnd+1; // skip (); return; } PStatement lambdaBlock = addStatement( @@ -2464,7 +2475,6 @@ void CppParser::handleLambda() false); scanMethodArgs(lambdaBlock,argStart,argEnd); addSoloScopeLevel(lambdaBlock,blockLine); - mIndex=bodyStart+1; // skip '{' } void CppParser::handleMethod(StatementKind functionKind,const QString &sType, const QString &sName, int argStart, bool isStatic, bool isFriend) @@ -2529,12 +2539,8 @@ void CppParser::handleMethod(StatementKind functionKind,const QString &sType, co int delimPos = sName.lastIndexOf("::"); QString scopelessName; QString parentClassName; - if (delimPos >= 0) { + if (splitLastMember(sName,scopelessName,parentClassName)) { // Provide Bar instead of Foo::Bar - scopelessName = sName.mid(delimPos+2); - - // Check what class this function belongs to - parentClassName = sName.mid(0, delimPos); scopeStatement = getIncompleteClass(parentClassName,getCurrentScope()); } else scopelessName = sName; @@ -2839,7 +2845,7 @@ void CppParser::handlePreprocessor() goto handlePreprocessorEnd; int delimPos = s.lastIndexOf(':'); if (delimPos>=0) { - qDebug()<line<line<text, mIndex+1, false, false); } else { - skipNextSemicolon(mIndex); + //error + moveToNextBraceOrSkipNextSemicolon(mIndex); } } else if (!isIdentChar(mTokenizer[mIndex]->text[0])) { - skipNextSemicolon(mIndex); + moveToNextBraceOrSkipNextSemicolon(mIndex); } else if (mTokenizer[mIndex]->text.endsWith('.') || mTokenizer[mIndex]->text.endsWith("->")) { - skipNextSemicolon(mIndex); + moveToNextBraceOrSkipNextSemicolon(mIndex); } else if (checkForKeyword(keywordType)) { // includes template now handleKeyword(keywordType); } else if (keywordType==KeywordType::For) { // (for/catch) @@ -3020,9 +3027,14 @@ bool CppParser::handleStatement() handleStructs(false); } else { // it should be method/constructor/var - checkAndHandleMethodOrVar(); + checkAndHandleMethodOrVar(keywordType); } Q_ASSERT(mIndex<999999); + + while (mTokenizer.lambdasCount()>0 && mTokenizer.indexOfFirstLambda()=mTokenizer.tokenCount()) return; - // Do not modifiy index initially - int i = mIndex; - - // Skip until the struct body starts - while ((i < mTokenizer.tokenCount()) && ! ( - mTokenizer[i]->text.front() ==';' - || mTokenizer[i]->text.front() =='{')) - i++; - + // Do not modifiy index + int i=indexOfNextSemicolonOrLeftBrace(mIndex); + if (i >= mTokenizer.tokenCount()) { + //error + mIndex=i; + return; + } // Forward class/struct decl *or* typedef, e.g. typedef struct some_struct synonym1, synonym2; - if ((i < mTokenizer.tokenCount()) && (mTokenizer[i]->text.front() == ';')) { + if (mTokenizer[i]->text.front() == ';') { // typdef struct Foo Bar if (isTypedef) { QString oldType = mTokenizer[mIndex]->text; @@ -3125,12 +3135,21 @@ void CppParser::handleStructs(bool isTypedef) || mTokenizer[mIndex + 1]->text.front() == '{' || mTokenizer[mIndex + 1]->text.front() == ':')) { QString command = mTokenizer[mIndex]->text; + + PStatement scopeStatement=getCurrentScope(); + QString scopelessName; + QString parentName; + if (splitLastMember(command,scopelessName,parentName)) { + scopeStatement = getIncompleteClass(parentName,getCurrentScope()); + } else { + scopelessName=command; + } if (!command.isEmpty()) { firstSynonym = addStatement( - getCurrentScope(), + scopeStatement, mCurrentFile, prefix, // type - command, // command + scopelessName, // command "", // args "", // no name args, "", // values @@ -4781,7 +4800,29 @@ QString CppParser::removeTemplateParams(const QString &phrase) bool CppParser::splitLastMember(const QString &token, QString &lastMember, QString &remaining) { - int pos = token.lastIndexOf("::"); + int pos = token.length()-1; + int level=0; + bool found=false; + while (pos>=0 && !found) { + switch(token[pos].unicode()) { + case ']': + case '>': + case ')': + level++; + break; + case '[': + case '<': + case '(': + level--; + break; + case ':': + if (level==0 && pos>0 && token[pos-1]==':') { + found=true; + break; + } + } + pos--; + } if (pos<0) return false; lastMember=token.mid(pos+2); @@ -4850,7 +4891,7 @@ bool CppParser::isNotFuncArgs(int startIndex) return true; if (!mCppTypeKeywords.contains(currentText)) { if (currentText=="true" || currentText=="false" || currentText=="nullptr" || - currentText=='this') + currentText=="this") return true; if (currentText=="const") return false; @@ -5015,6 +5056,26 @@ void CppParser::skipNextSemicolon(int index) } } +void CppParser::moveToNextBraceOrSkipNextSemicolon(int index) +{ + mIndex=index; + while (mIndextext[0].unicode()) { + case ';': + mIndex++; + return; + case '{': + mIndex = mTokenizer[mIndex]->matchIndex; + return; + case '(': + mIndex = mTokenizer[mIndex]->matchIndex+1; + break; + default: + mIndex++; + } + } +} + void CppParser::skipParenthesis(int index) { mIndex=index; diff --git a/RedPandaIDE/parser/cppparser.h b/RedPandaIDE/parser/cppparser.h index d2892529..66156c9a 100644 --- a/RedPandaIDE/parser/cppparser.h +++ b/RedPandaIDE/parser/cppparser.h @@ -222,7 +222,7 @@ private: bool checkForTypedefStruct(); bool checkForUsing(KeywordType keywordType); - void checkAndHandleMethodOrVar(); + void checkAndHandleMethodOrVar(KeywordType keywordType); void fillListOfFunctions(const QString& fileName, int line, const PStatement& statement, @@ -412,7 +412,7 @@ private: void handleEnum(bool isTypedef); void handleForBlock(); void handleKeyword(KeywordType skipType); - void handleLambda(); + void handleLambda(int index); void handleMethod( StatementKind functionKind, const QString& sType, @@ -586,6 +586,7 @@ private: int indexPassParenthesis(int index); int indexPassBraces(int index); void skipNextSemicolon(int index); + void moveToNextBraceOrSkipNextSemicolon(int index); void skipParenthesis(int index); QString mergeArgs(int startIndex, int endIndex); void parseCommandTypeAndArgs(QString& command, diff --git a/RedPandaIDE/parser/cpptokenizer.cpp b/RedPandaIDE/parser/cpptokenizer.cpp index 6f975c5c..4ade57ee 100644 --- a/RedPandaIDE/parser/cpptokenizer.cpp +++ b/RedPandaIDE/parser/cpptokenizer.cpp @@ -34,6 +34,7 @@ void CppTokenizer::clear() mUnmatchedBraces.clear(); mUnmatchedBrackets.clear(); mUnmatchedParenthesis.clear(); + mLambdas.clear(); } void CppTokenizer::tokenize(const QStringList &buffer) @@ -153,6 +154,8 @@ void CppTokenizer::addToken(const QString &sText, int iLine, TokenType tokenType mUnmatchedParenthesis.pop_back(); } break; + case TokenType::LambdaCaptures: + mLambdas.push_back(mTokenList.count()); default: break; } @@ -570,18 +573,18 @@ void CppTokenizer::skipDoubleQuotes() } } -void CppTokenizer::skipPair(const QChar &cStart, const QChar cEnd, const QSet& failChars) +void CppTokenizer::skipPair(const QChar &cStart, const QChar cEnd, bool keepLambda) { mCurrent++; while (*mCurrent != 0) { - if ((*mCurrent == '(') && !failChars.contains('(')) { - skipPair('(', ')', failChars); - } else if ((*mCurrent == '[') && !failChars.contains('[')) { - skipPair('[', ']', failChars); - } else if ((*mCurrent == '{') && !failChars.contains('{')) { - skipPair('{', '}', failChars); + if (*mCurrent == '(') { + skipPair('(', ')',keepLambda); + } else if (*mCurrent == '[') { + skipPair('[', ']',keepLambda); + } else if (*mCurrent == '{') { + skipPair('{', '}',keepLambda); } else if (*mCurrent == cStart) { - skipPair(cStart, cEnd, failChars); + skipPair(cStart, cEnd); } else if (*mCurrent == cEnd) { mCurrent++; // skip over end break; @@ -745,6 +748,21 @@ bool CppTokenizer::isIdentChar(const QChar &ch) return ch=='_' || ch.isLetter() ; } +int CppTokenizer::lambdasCount() const +{ + return mLambdas.count(); +} + +int CppTokenizer::indexOfFirstLambda() const +{ + return mLambdas.front(); +} + +void CppTokenizer::removeFirstLambda() +{ + mLambdas.pop_front(); +} + void CppTokenizer::advance() { switch(mCurrent->unicode()) { diff --git a/RedPandaIDE/parser/cpptokenizer.h b/RedPandaIDE/parser/cpptokenizer.h index c40c4ae8..de3d3f5c 100644 --- a/RedPandaIDE/parser/cpptokenizer.h +++ b/RedPandaIDE/parser/cpptokenizer.h @@ -51,6 +51,10 @@ public: PToken operator[](int i); int tokenCount(); bool isIdentChar(const QChar& ch); + int lambdasCount() const; + int indexOfFirstLambda() const; + void removeFirstLambda(); + private: void addToken(const QString& sText, int iLine, TokenType tokenType); void advance(); @@ -77,7 +81,7 @@ private: void simplifyArgs(QString& output); void skipAssignment(); void skipDoubleQuotes(); - void skipPair(const QChar& cStart, const QChar cEnd, const QSet& failChars = QSet()); + void skipPair(const QChar& cStart, const QChar cEnd); bool skipAngleBracketPair(); void skipRawString(); void skipSingleQuote(); @@ -105,9 +109,10 @@ private: int mCurrentLine; QString mLastToken; TokenList mTokenList; - QList mUnmatchedBraces; // stack of indices for unmatched '{' - QList mUnmatchedBrackets; // stack of indices for unmatched '[' - QList mUnmatchedParenthesis;// stack of indices for unmatched '(' + QList mLambdas; + QVector mUnmatchedBraces; // stack of indices for unmatched '{' + QVector mUnmatchedBrackets; // stack of indices for unmatched '[' + QVector mUnmatchedParenthesis;// stack of indices for unmatched '(' }; using PCppTokenizer = std::shared_ptr; diff --git a/RedPandaIDE/parser/parserutils.cpp b/RedPandaIDE/parser/parserutils.cpp index 21c171a4..fbb2fd98 100644 --- a/RedPandaIDE/parser/parserutils.cpp +++ b/RedPandaIDE/parser/parserutils.cpp @@ -113,7 +113,6 @@ void initParser() CppKeywords.insert("__attribute",KeywordType::SkipNextParenthesis); CppKeywords.insert("alignas",KeywordType::SkipNextParenthesis); // not right CppKeywords.insert("alignof",KeywordType::SkipNextParenthesis); // not right - CppKeywords.insert("decltype",KeywordType::SkipNextParenthesis); // not right CppKeywords.insert("if",KeywordType::SkipNextParenthesis); CppKeywords.insert("sizeof",KeywordType::SkipNextParenthesis); CppKeywords.insert("switch",KeywordType::SkipNextParenthesis); @@ -199,6 +198,8 @@ void initParser() CppKeywords.insert("using",KeywordType::Using); CppKeywords.insert("protected",KeywordType::Protected); CppKeywords.insert("friend",KeywordType::Friend); + CppKeywords.insert("decltype",KeywordType::DeclType); // not right + // nullptr is value CppKeywords.insert("nullptr",KeywordType::None); diff --git a/RedPandaIDE/parser/parserutils.h b/RedPandaIDE/parser/parserutils.h index 2004a111..fd3bc1e4 100644 --- a/RedPandaIDE/parser/parserutils.h +++ b/RedPandaIDE/parser/parserutils.h @@ -74,6 +74,7 @@ enum class KeywordType { Namespace, //namespace Typedef, //typedef Using, //using + DeclType, // decltype None, // It's a keyword but don't process here NotKeyword };