AST: Fix AST for lambda '[&]{..}'

This commit is contained in:
Daniel Marjamäki 2017-04-09 17:49:55 +02:00
parent 59b0c6f6b1
commit e6005dfa3c
2 changed files with 33 additions and 20 deletions

View File

@ -677,34 +677,40 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
} else } else
compileBinOp(tok, state, compileScope); compileBinOp(tok, state, compileScope);
} else if (tok->str() == "[") { } else if (tok->str() == "[") {
bool lambda = false; if (state.cpp && isPrefixUnary(tok, state.cpp) && Token::Match(tok->link(), " ] (|{")) { // Lambda
if (state.cpp && isPrefixUnary(tok, state.cpp) && tok->link()->strAt(1) == "(") { // Lambda
// What we do here: // What we do here:
// - Nest the round bracket under the square bracket. // - Nest the round bracket under the square bracket.
// - Nest what follows the lambda (if anything) with the lambda opening [ // - Nest what follows the lambda (if anything) with the lambda opening [
// - Compile the content of the lambda function as separate tree (this is done later) // - Compile the content of the lambda function as separate tree (this is done later)
// this must be consistent with isLambdaCaptureList // this must be consistent with isLambdaCaptureList
Token* squareBracket = tok; Token* const squareBracket = tok;
Token* roundBracket = squareBracket->link()->next(); if (Token::simpleMatch(squareBracket->link(), "] (")) {
Token* curlyBracket = roundBracket->link()->next(); Token* const roundBracket = squareBracket->link()->next();
while (Token::Match(curlyBracket, "%name%|.|::")) Token* curlyBracket = roundBracket->link()->next();
curlyBracket = curlyBracket->next(); while (Token::Match(curlyBracket, "%name%|.|::"))
if (Token::simpleMatch(curlyBracket, "{")) { curlyBracket = curlyBracket->next();
lambda = true; if (curlyBracket && curlyBracket->str() == "{") {
squareBracket->astOperand1(roundBracket); squareBracket->astOperand1(roundBracket);
roundBracket->astOperand1(curlyBracket); roundBracket->astOperand1(curlyBracket);
state.op.push(squareBracket);
tok = curlyBracket->link()->next();
continue;
}
} else {
Token* const curlyBracket = squareBracket->link()->next();
squareBracket->astOperand1(curlyBracket);
state.op.push(squareBracket); state.op.push(squareBracket);
tok = curlyBracket->link()->next(); tok = curlyBracket->link()->next();
continue;
} }
} }
if (!lambda) {
Token* tok2 = tok; Token* tok2 = tok;
if (tok->strAt(1) != "]") if (tok->strAt(1) != "]")
compileBinOp(tok, state, compileExpression); compileBinOp(tok, state, compileExpression);
else else
compileUnaryOp(tok, state, compileExpression); compileUnaryOp(tok, state, compileExpression);
tok = tok2->link()->next(); tok = tok2->link()->next();
}
} else if (tok->str() == "(" && (!iscast(tok) || Token::Match(tok->previous(), "if|while|for|switch|catch"))) { } else if (tok->str() == "(" && (!iscast(tok) || Token::Match(tok->previous(), "if|while|for|switch|catch"))) {
Token* tok2 = tok; Token* tok2 = tok;
tok = tok->next(); tok = tok->next();
@ -986,11 +992,13 @@ static bool isLambdaCaptureList(const Token * tok)
{ {
// a lambda expression '[x](y){}' is compiled as: // a lambda expression '[x](y){}' is compiled as:
// [ // [
// `-( // `-( <<-- optional
// `-{ // `-{
// see compilePrecedence2 // see compilePrecedence2
if (tok->str() != "[") if (tok->str() != "[")
return false; return false;
if (Token::simpleMatch(tok->astOperand1(), "{"))
return true;
if (!tok->astOperand1() || tok->astOperand1()->str() != "(") if (!tok->astOperand1() || tok->astOperand1()->str() != "(")
return false; return false;
const Token * params = tok->astOperand1(); const Token * params = tok->astOperand1();
@ -1035,6 +1043,9 @@ static void createAstAtTokenInner(Token * const tok1, const Token *endToken, boo
tok = createAstAtToken(tok, cpp); tok = createAstAtToken(tok, cpp);
} else if (tok->str() == "[") { } else if (tok->str() == "[") {
if (isLambdaCaptureList(tok)) { if (isLambdaCaptureList(tok)) {
tok = const_cast<Token *>(tok->astOperand1());
if (tok->str() == "(")
tok = const_cast<Token *>(tok->astOperand1());
const Token * const endToken2 = tok->link(); const Token * const endToken2 = tok->link();
for (; tok && tok != endToken && tok != endToken2; tok = tok ? tok->next() : nullptr) for (; tok && tok != endToken && tok != endToken2; tok = tok ? tok->next() : nullptr)
tok = createAstAtToken(tok, cpp); tok = createAstAtToken(tok, cpp);

View File

@ -8167,6 +8167,8 @@ private:
ASSERT_EQUALS("{([cd,(return 0return", testAst("return [](int a, int b) -> int { return 0; }(c, d);")); ASSERT_EQUALS("{([cd,(return 0return", testAst("return [](int a, int b) -> int { return 0; }(c, d);"));
ASSERT_EQUALS("x{([= 0return", testAst("x = [](){return 0; };")); ASSERT_EQUALS("x{([= 0return", testAst("x = [](){return 0; };"));
ASSERT_EQUALS("ab{[(= cd=", testAst("a = b([&]{c=d;});"));
} }
void compileLimits() { void compileLimits() {