work done: lambda support

This commit is contained in:
Roy Qu 2022-11-02 22:48:25 +08:00
parent bd04e013de
commit baab677fa1
5 changed files with 182 additions and 43 deletions

View File

@ -1394,11 +1394,20 @@ bool CppParser::isCurrentScope(const QString &command)
return false;
QString s = command;
// remove template staff
int i= command.indexOf('<');
if (i>=0) {
s.truncate(i);
if (s.endsWith('>')) {
int i= command.indexOf('<');
if (i>=0) {
s.truncate(i);
}
}
return (statement->command == s);
QString s2 = statement->command;
if (s2.endsWith('>')) {
int i= s2.indexOf('<');
if (i>=0) {
s2.truncate(i);
}
}
return (s2 == s);
}
void CppParser::addSoloScopeLevel(PStatement& statement, int line, bool shouldResetBlock)
@ -1437,6 +1446,7 @@ void CppParser::addSoloScopeLevel(PStatement& statement, int line, bool shouldRe
else
mClassScope = StatementClassScope::Public; // structs are public by default
mCurrentClassScope.append(mClassScope);
//qDebug()<<"++add scope"<<mCurrentFile<<line<<mCurrentClassScope.count();
}
void CppParser::removeScopeLevel(int line)
@ -1444,6 +1454,7 @@ void CppParser::removeScopeLevel(int line)
// Remove class list
if (mCurrentScope.isEmpty())
return; // TODO: should be an exception
//qDebug()<<"--remove scope"<<mCurrentFile<<line<<mCurrentClassScope.count();
PStatement currentScope = getCurrentScope();
PFileIncludes fileIncludes = mPreprocessor.includesList().value(mCurrentFile);
if (currentScope && (currentScope->kind == StatementKind::skBlock)) {
@ -1604,6 +1615,9 @@ bool CppParser::checkForMethod(QString &sType, QString &sName, int &argStartInde
//it's not a function define
if (indexAfter>=mTokenizer.tokenCount())
break;
//it's not a function define;
if (isInvalidFunctionArgsSuffixChar(mTokenizer[indexAfter]->text[0]))
break;
//it's not a function define
if (mTokenizer[indexAfter]->text[0] == ';') {
//function can only be defined in global/namespaces/classes
@ -1626,12 +1640,11 @@ bool CppParser::checkForMethod(QString &sType, QString &sName, int &argStartInde
bTypeOK = !sType.isEmpty();
bNameOK = !sName.isEmpty();
bArgsOK = true;
mIndex = argEndIndex+1;
// Allow constructor/destructor too
if (!bTypeOK) {
// Check for constructor/destructor outside class body
int delimPos = sName.indexOf("::");
int delimPos = sName.lastIndexOf("::");
if (delimPos >= 0) {
bTypeOK = true;
sType = sName.mid(0, delimPos);
@ -1652,6 +1665,7 @@ bool CppParser::checkForMethod(QString &sType, QString &sName, int &argStartInde
sType.remove(0,1);
bTypeOK = isCurrentScope(sType); // constructor/destructor
}
mIndex = argEndIndex+1;
break;
} else {
//if IsValidIdentifier(mTokenizer[mIndex]->text) then
@ -1694,6 +1708,13 @@ bool CppParser::checkForPreprocessor()
return (mTokenizer[mIndex]->text.startsWith('#'));
}
bool CppParser::checkForLambda()
{
return (mIndex+1<mTokenizer.tokenCount()
&& mTokenizer[mIndex]->text.startsWith('[')
&& mTokenizer[mIndex+1]->text=='(');
}
bool CppParser::checkForScope(KeywordType keywordType)
{
return ( (keywordType == KeywordType::Public || keywordType == KeywordType::Protected
@ -1970,8 +1991,7 @@ void CppParser::handleCatchBlock()
true,
false);
addSoloScopeLevel(block,startLine);
if (!mTokenizer[mIndex+1]->text.contains("..."))
scanMethodArgs(block,mIndex, mTokenizer[mIndex]->matchIndex);
scanMethodArgs(block,mIndex, mTokenizer[mIndex]->matchIndex);
mIndex=mTokenizer[mIndex]->matchIndex+1;
}
@ -2237,6 +2257,37 @@ void CppParser::handleKeyword(KeywordType skipType)
}
}
void CppParser::handleLambda()
{
int startLine=mTokenizer[mIndex]->line;
int argStart=mIndex+1;
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(
getCurrentScope(),
mCurrentFile,
"",
"",
"",
"",
"",
startLine,
StatementKind::skBlock,
StatementScope::Local,
StatementClassScope::None,
true,
false);
scanMethodArgs(lambdaBlock,argStart,argEnd);
addSoloScopeLevel(lambdaBlock,blockLine);
mIndex=bodyStart+1; // skip '{'
}
void CppParser::handleMethod(const QString &sType, const QString &sName, int argStart, int argEnd, bool isStatic, bool isFriend)
{
bool isValid = true;
@ -2247,26 +2298,42 @@ void CppParser::handleMethod(const QString &sType, const QString &sName, int arg
return;
PStatement functionClass = getCurrentScope();
//find start of the function body;
bool foundColon=false;
while ((mIndex < mTokenizer.tokenCount()) && !isblockChar(mTokenizer[mIndex]->text.front())) {
if (mTokenizer[mIndex]->text=='(') {
mIndex=mTokenizer[mIndex]->matchIndex+1;
}else if (mTokenizer[mIndex]->text==':') {
foundColon=true;
break;
} else
mIndex++;
}
if (foundColon) {
mIndex++;
while ((mIndex < mTokenizer.tokenCount()) && !isblockChar(mTokenizer[mIndex]->text.front())) {
if (isWordChar(mTokenizer[mIndex]->text[0])
&& mIndex+1<mTokenizer.tokenCount()
&& mTokenizer[mIndex+1]->text=='{') {
//skip parent {}intializer
mIndex=mTokenizer[mIndex+1]->matchIndex+1;
} else if (mTokenizer[mIndex]->text=='(') {
mIndex=mTokenizer[mIndex]->matchIndex+1;
}else if (mTokenizer[mIndex]->text==':') {
foundColon=true;
break;
} else
mIndex++;
}
}
// Check if this is a prototype
if (mTokenizer[mIndex]->text.startsWith(';')
|| mTokenizer[mIndex]->text.startsWith('}')) {// prototype
isDeclaration = true;
} else {
// Find the function body start after the inherited constructor
if ((mIndex < mTokenizer.tokenCount()) && mTokenizer[mIndex]->text.startsWith(':')) {
while ((mIndex < mTokenizer.tokenCount()) && !isblockChar(mTokenizer[mIndex]->text.front())) {
if (mTokenizer[mIndex]->text=='(')
mIndex=mTokenizer[mIndex]->matchIndex+1;
else
mIndex++;
}
}
// Still a prototype
if ((mIndex < mTokenizer.tokenCount()) && (mTokenizer[mIndex]->text.startsWith(';')
|| mTokenizer[mIndex]->text.startsWith('}'))) {// prototype
isDeclaration = true;
}
}
QString scopelessName;
@ -2728,6 +2795,10 @@ bool CppParser::handleStatement()
mIndex++;
} else if (checkForPreprocessor()) {
handlePreprocessor();
} else if (checkForLambda()) { // is lambda
handleLambda();
} else if (!isLetterChar(mTokenizer[mIndex]->text[0])) {
mIndex++;
} else if (checkForKeyword(keywordType)) { // includes template now
handleKeyword(keywordType);
} else if (keywordType==KeywordType::For) { // (for/catch)
@ -3138,8 +3209,8 @@ bool CppParser::tryHandleVar()
bool isStatic = false;
QString lastType;
if (isInvalidVarPrefixChar(mTokenizer[mIndex]->text.front())
|| (mTokenizer[mIndex]->text.back() == '.')
|| (mTokenizer[mIndex]->text.back() == '>'))
|| mTokenizer[mIndex]->text.endsWith('.')
|| mTokenizer[mIndex]->text.endsWith("->"))
//failed to handle
return false;
if (varType=="extern") {
@ -3155,19 +3226,23 @@ bool CppParser::tryHandleVar()
if (mIndex>=mTokenizer.tokenCount()
|| checkForKeyword(keywordType)
|| isInvalidVarPrefixChar(mTokenizer[mIndex]->text.front())
|| (mTokenizer[mIndex]->text.back() == '.')
|| (mTokenizer[mIndex]->text.back() == '>')) {
|| mTokenizer[mIndex]->text.endsWith('.')
|| mTokenizer[mIndex]->text.endsWith("->")) {
//failed to handle
mIndex=indexBackup;
return false;
}
while (mIndex+1<mTokenizer.tokenCount()) {
if (mTokenizer[mIndex]->text=='('
&& mTokenizer[mIndex]->matchIndex<=mTokenizer.tokenCount()
if (mTokenizer[mIndex]->text=='(') {
if ( mTokenizer[mIndex]->matchIndex<=mTokenizer.tokenCount()
&& mTokenizer[mTokenizer[mIndex]->matchIndex]->text=='(') {
//function pointer
break;
//function pointer
break;
}
//error break;
mIndex=indexBackup;
return false;
} else if (mTokenizer[mIndex + 1]->text=='('
|| mTokenizer[mIndex + 1]->text==','
|| mTokenizer[mIndex + 1]->text==';'
@ -3320,7 +3395,6 @@ void CppParser::internalParse(const QString &fileName)
mPreprocessor.preprocess(fileName, buffer);
QStringList preprocessResult = mPreprocessor.result();
stringsToFile(mPreprocessor.result(),QString("r:\\preprocess-%1.txt").arg(extractFileName(fileName)));
#ifdef QT_DEBUG
// stringsToFile(mPreprocessor.result(),QString("r:\\preprocess-%1.txt").arg(extractFileName(fileName)));
// mPreprocessor.dumpDefinesTo("r:\\defines.txt");
@ -3335,19 +3409,17 @@ void CppParser::internalParse(const QString &fileName)
preprocessResult.clear();
if (mTokenizer.tokenCount() == 0)
return;
#ifdef QT_DEBUG
// mTokenizer.dumpTokens(QString("r:\\tokens-%1.txt").arg(extractFileName(fileName)));
#endif
// Process the token list
while(true) {
if (!handleStatement())
break;
}
mTokenizer.dumpTokens(QString("r:\\tokens-%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)));
#ifdef QT_DEBUG
// mTokenizer.dumpTokens(QString("r:\\tokens-%1.txt").arg(extractFileName(fileName)));
//
// mStatementList.dumpAll("r:\\all-stats.txt");
// 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();
@ -4647,8 +4719,12 @@ bool CppParser::isNotFuncArgs(int startIndex, int endIndex)
return true;
if (isLetterChar(ch)) {
QString currentText=mTokenizer[i]->text;
while (currentText.startsWith('*')
|| currentText.startsWith('&'))
currentText.remove(0,1);
if (!mCppTypeKeywords.contains(currentText)) {
if (currentText=="true" || currentText=="false" || currentText=="nullptr" )
if (currentText=="true" || currentText=="false" || currentText=="nullptr" ||
currentText=='this')
return true;
if (currentText=="const" )
return false;

View File

@ -214,6 +214,7 @@ private:
int &argEndIndex, bool &isStatic, bool &isFriend); // caching of results
bool checkForNamespace(KeywordType keywordType);
bool checkForPreprocessor();
bool checkForLambda();
bool checkForScope(KeywordType keywordType);
void checkForSkipStatement();
bool checkForStructs(KeywordType keywordType);
@ -399,6 +400,7 @@ private:
void handleEnum(bool isTypedef);
void handleForBlock();
void handleKeyword(KeywordType skipType);
void handleLambda();
void handleMethod(
const QString& sType,
const QString& sName,
@ -464,6 +466,23 @@ private:
return (ch>='0' && ch<='9');
}
bool isInvalidFunctionArgsSuffixChar(const QChar& ch) const {
switch(ch.unicode()){
case '.':
case '-':
case '+':
case '/':
case '%':
case '&':
case '*':
case '|':
case '?':
return true;
default:
return false;
}
}
/*'(', ';', ':', '{', '}', '#' */
bool isSeperator(const QChar& ch) const {
switch(ch.unicode()){

View File

@ -18,6 +18,7 @@
#include <QFile>
#include <QTextStream>
#include <QDebug>
CppTokenizer::CppTokenizer()
{
@ -154,7 +155,6 @@ void CppTokenizer::addToken(const QString &sText, int iLine, TokenType tokenType
default:
break;
}
mTokenList.append(token);
}
@ -167,6 +167,15 @@ void CppTokenizer::countLines()
}
}
QString CppTokenizer::getLambdaCaptures()
{
QChar* offset = mCurrent;
skipPair('[', ']');
QString result(offset,mCurrent-offset);
skipToNextToken();
return result;
}
QString CppTokenizer::getForInit()
{
QChar* startOffset = mCurrent;
@ -195,6 +204,7 @@ QString CppTokenizer::getForInit()
QString CppTokenizer::getNextToken(TokenType *pTokenType, bool bSkipArray, bool bSkipBlock)
{
QString result;
int backupIndex;
bool done = false;
*pTokenType=TokenType::Normal;
while (true) {
@ -246,6 +256,7 @@ QString CppTokenizer::getNextToken(TokenType *pTokenType, bool bSkipArray, bool
countLines();
mCurrent+=2;
result = "::";
skipToNextToken();
// Append next token to this one
if (isIdentChar(*mCurrent))
result+=getWord(true, bSkipArray, bSkipBlock);
@ -278,6 +289,34 @@ QString CppTokenizer::getNextToken(TokenType *pTokenType, bool bSkipArray, bool
advance();
done = true;
break;
case '[':
{
// QChar* backup=mCurrent;
// skipPair('[',']');
// skipToNextToken();
// qDebug()<<*mCurrent;
// if (*mCurrent!='(') {
// mCurrent=backup;
// advance();
// } else {
// mCurrent=backup;
// skipPair('[',']');
// *pTokenType=TokenType::LambdaCaptures;
// countLines();
// result = QString(backup,mCurrent-backup);
// done = true;
// qDebug()<<"yes"<<result;
// }
*pTokenType=TokenType::LambdaCaptures;
countLines();
QChar* backup=mCurrent;
skipPair('[',']');
result = QString(backup,mCurrent-backup);
done = true;
// qDebug()<<"yes"<<result;
break;
}
case ')':
*pTokenType=TokenType::RightParenthesis;
countLines();
@ -425,6 +464,7 @@ QString CppTokenizer::getWord(bool bSkipParenthesis, bool bSkipArray, bool bSkip
if (result != "using") {
result+=QString(mCurrent,2);
mCurrent+=2;
skipToNextToken();
if (isIdentChar(*mCurrent)) {
// Append next token to this one
QString s = getWord(bSkipParenthesis, bSkipArray, bSkipBlock);
@ -765,7 +805,7 @@ bool CppTokenizer::isLineChar(const QChar &ch)
bool CppTokenizer::isBlankChar(const QChar &ch)
{
return (ch<=32);
return (ch<=32) && (ch>0);
}
bool CppTokenizer::isOperatorChar(const QChar &ch)

View File

@ -31,6 +31,7 @@ class CppTokenizer
LeftBracket,
RightBracket,
Assignment,
LambdaCaptures
};
public:
@ -55,6 +56,7 @@ private:
void advance();
void countLines();
PToken getToken(int index);
QString getLambdaCaptures();
QString getForInit();
QString getNextToken(

View File

@ -650,6 +650,8 @@ StatementKind getKindOfStatement(const PStatement& statement)
} else {
return StatementKind::skVariable;
}
} else if (statement->kind == StatementKind::skParameter) {
return StatementKind::skLocalVariable;
}
return statement->kind;
}