Commit 5fc52a67 authored by David Nolden's avatar David Nolden

Add full support for foreach statements into the parser and duchain. Add a...

Add full support for foreach statements into the parser and duchain. Add a test to verify the functionality.
parent 1a94901e
[CMake]
CMakeDir=/home/nolden/kdedev/4.0/qt-copy/share/cmake/Modules
[Project]
Name=KDevelop
Manager=KDevCMakeManager
Name=KDevelop
......@@ -482,6 +482,34 @@ void TestDUChain::testDeclareFor()
release(top);
}
void TestDUChain::testDeclareForeach()
{
TEST_FILE_PARSE_ONLY
// 0 1 2 3 4 5
// 012345678901234567890123456789012345678901234567890123456789
QByteArray method("struct IntList{}; int main() { foreach (int i, IntList) { i += 3; } }");
DUContext* top = parse(method, DumpAll);
DUChainWriteLocker lock(DUChain::lock());
QVERIFY(!top->parentContext());
QCOMPARE(top->childContexts().count(), 3);
QCOMPARE(top->localDeclarations().count(), 2);
QVERIFY(top->localScopeIdentifier().isEmpty());
QCOMPARE(top->localDeclarations()[0]->uses().count(), 1);
DUContext* mainContext = top->childContexts()[2];
QCOMPARE(mainContext->childContexts().count(), 2);
QCOMPARE(mainContext->childContexts()[0]->localDeclarations().count(), 1);
QCOMPARE(mainContext->childContexts()[1]->localDeclarations().count(), 0);
QCOMPARE(mainContext->childContexts()[0]->localDeclarations()[0]->uses().count(), 1);
release(top);
}
void TestDUChain::testEnum()
{
TEST_FILE_PARSE_ONLY
......
......@@ -63,6 +63,7 @@ private slots:
void testIntegralTypes();
void testArrayType();
void testDeclareFor();
void testDeclareForeach();
void testVariableDeclaration();
void testDeclareStruct();
void testDeclareClass();
......
......@@ -448,6 +448,7 @@ struct FunctionDefinitionAST: public DeclarationAST
CtorInitializerAST *constructor_initializers;
};
//ForStatementAST is also used for foreach statements, but for them only init_statement is non-zero.
struct ForStatementAST: public StatementAST
{
DECLARE_AST_NODE(ForStatement)
......
......@@ -1387,15 +1387,27 @@ void Lexer::scanKeyword7()
{
case 'd':
if (*(cursor + 1) == 'e' &&
*(cursor + 2) == 'f' &&
*(cursor + 3) == 'a' &&
*(cursor + 4) == 'u' &&
*(cursor + 5) == 'l' &&
*(cursor + 6) == 't')
{
(*session->token_stream)[index++].kind = Token_default;
return;
}
*(cursor + 2) == 'f' &&
*(cursor + 3) == 'a' &&
*(cursor + 4) == 'u' &&
*(cursor + 5) == 'l' &&
*(cursor + 6) == 't')
{
(*session->token_stream)[index++].kind = Token_default;
return;
}
break;
case 'f':
if (*(cursor + 1) == 'o' &&
*(cursor + 2) == 'r' &&
*(cursor + 3) == 'e' &&
*(cursor + 4) == 'a' &&
*(cursor + 5) == 'c' &&
*(cursor + 6) == 'h')
{
(*session->token_stream)[index++].kind = Token_foreach;
return;
}
break;
case 'm':
......
......@@ -375,6 +375,7 @@ bool Parser::skipUntilStatement()
case Token_while:
case Token_do:
case Token_for:
case Token_foreach:
case Token_break:
case Token_continue:
case Token_return:
......@@ -1756,13 +1757,15 @@ bool Parser::parseTypeId(TypeIdAST *&node)
return true;
}
bool Parser::parseInitDeclaratorList(const ListNode<InitDeclaratorAST*> *&node)
bool Parser::parseInitDeclaratorList(const ListNode<InitDeclaratorAST*> *&node, bool onlyOneDeclarator)
{
InitDeclaratorAST *decl = 0;
if (!parseInitDeclarator(decl))
return false;
node = snoc(node, decl, session->mempool);
if(onlyOneDeclarator)
return true;
while (session->token_stream->lookAhead() == ',')
{
......@@ -2624,6 +2627,7 @@ bool Parser::parseStatement(StatementAST *&node)
return parseDoStatement(node);
case Token_for:
case Token_foreach:
return parseForStatement(node);
case Token_if:
......@@ -2854,19 +2858,30 @@ bool Parser::parseForStatement(StatementAST *&node)
{
std::size_t start = session->token_stream->cursor();
ADVANCE(Token_for, "for");
ADVANCE('(', "(");
int tok = session->token_stream->lookAhead();
StatementAST *init = 0;
if (!parseForInitStatement(init))
{
reportError(("for initialization expected"));
return false;
}
if(tok == Token_foreach) {
ADVANCE(Token_foreach, "foreach");
}else{
ADVANCE(Token_for, "for");
}
ADVANCE('(', "(");
if (!parseForInitStatement(init, tok == Token_foreach))
{
reportError(("for initialization expected"));
return false;
}
ConditionAST *cond = 0;
parseCondition(cond);
ADVANCE(';', ";");
if(tok != Token_foreach) {
parseCondition(cond);
ADVANCE(';', ";");
}
ExpressionAST *expr = 0;
parseCommaExpression(expr);
......@@ -2888,11 +2903,14 @@ bool Parser::parseForStatement(StatementAST *&node)
return true;
}
bool Parser::parseForInitStatement(StatementAST *&node)
bool Parser::parseForInitStatement(StatementAST *&node, bool isForeach)
{
if (parseDeclarationStatement(node))
if (parseDeclarationStatement(node, isForeach))
return true;
if(isForeach)
return false;
return parseExpressionStatement(node);
}
......@@ -3071,7 +3089,7 @@ bool Parser::parseLabeledStatement(StatementAST *&node)
return false;
}
bool Parser::parseBlockDeclaration(DeclarationAST *&node)
bool Parser::parseBlockDeclaration(DeclarationAST *&node, bool onlyOneDeclarator)
{
switch(session->token_stream->lookAhead())
{
......@@ -3109,9 +3127,10 @@ bool Parser::parseBlockDeclaration(DeclarationAST *&node)
spec->cv = cv;
const ListNode<InitDeclaratorAST*> *declarators = 0;
parseInitDeclaratorList(declarators);
parseInitDeclaratorList(declarators, onlyOneDeclarator);
if (session->token_stream->lookAhead() != ';')
if (session->token_stream->lookAhead() != ';' && (!onlyOneDeclarator || session->token_stream->lookAhead() != ',') )
{
rewind(start);
return false;
......@@ -3158,12 +3177,12 @@ bool Parser::parseNamespaceAliasDefinition(DeclarationAST *&node)
return true;
}
bool Parser::parseDeclarationStatement(StatementAST *&node)
bool Parser::parseDeclarationStatement(StatementAST *&node, bool onlyOneDeclarator)
{
std::size_t start = session->token_stream->cursor();
DeclarationAST *decl = 0;
if (!parseBlockDeclaration(decl))
if (!parseBlockDeclaration(decl, onlyOneDeclarator))
return false;
DeclarationStatementAST *ast = CreateNode<DeclarationStatementAST>(session->mempool);
......
......@@ -97,7 +97,7 @@ public:
bool parseAssignmentExpression(ExpressionAST *&node);
bool parseBaseClause(BaseClauseAST *&node);
bool parseBaseSpecifier(BaseSpecifierAST *&node);
bool parseBlockDeclaration(DeclarationAST *&node);
bool parseBlockDeclaration(DeclarationAST *&node, bool onlyOneDeclarator = false);
bool parseCastExpression(ExpressionAST *&node);
bool parseClassSpecifier(TypeSpecifierAST *&node);
bool parseCommaExpression(ExpressionAST *&node);
......@@ -109,7 +109,7 @@ public:
bool parseCvQualify(const ListNode<std::size_t> *&node);
bool parseDeclaration(DeclarationAST *&node);
bool parseDeclarationInternal(DeclarationAST *&node);
bool parseDeclarationStatement(StatementAST *&node);
bool parseDeclarationStatement(StatementAST *&node, bool onlyOneDeclarator = false);
bool parseDeclarator(DeclaratorAST *&node);
bool parseDeleteExpression(ExpressionAST *&node);
bool parseDoStatement(StatementAST *&node);
......@@ -124,15 +124,16 @@ public:
bool parseExpression(ExpressionAST *&node);
bool parseExpressionOrDeclarationStatement(StatementAST *&node);
bool parseExpressionStatement(StatementAST *&node);
bool parseForInitStatement(StatementAST *&node);
bool parseForInitStatement(StatementAST *&node, bool isForeach);
bool parseForStatement(StatementAST *&node);
bool parseForeachStatement(StatementAST *&node);
bool parseFunctionBody(StatementAST *&node);
bool parseFunctionSpecifier(const ListNode<std::size_t> *&node);
bool parseIfStatement(StatementAST *&node);
bool parseInclusiveOrExpression(ExpressionAST *&node,
bool templArgs = false);
bool parseInitDeclarator(InitDeclaratorAST *&node);
bool parseInitDeclaratorList(const ListNode<InitDeclaratorAST*> *&node);
bool parseInitDeclaratorList(const ListNode<InitDeclaratorAST*> *&node, bool onlyOneDeclarator = false);
bool parseInitializer(InitializerAST *&node);
bool parseInitializerClause(InitializerClauseAST *&node);
bool parseLabeledStatement(StatementAST *&node);
......
......@@ -70,6 +70,7 @@ enum TOKEN_KIND
Token_false,
Token_float,
Token_for,
Token_foreach,
Token_friend,
Token_geq,
Token_goto,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment