Commit da2aa0df authored by Flex Ferrum's avatar Flex Ferrum Committed by Roberto Raggi

C++: Add support for C++11 range-based 'for' loops

Change-Id: I7eef048a7952a79f031ae3d0abba68e3c5ffbfb8
Reviewed-by: default avatarRoberto Raggi <roberto.raggi@nokia.com>
parent 7f943cae
......@@ -4343,3 +4343,61 @@ unsigned DecltypeSpecifierAST::lastToken() const
return 1;
}
/** \generated */
unsigned RangeBasedForStatementAST::firstToken() const
{
if (for_token)
return for_token;
if (lparen_token)
return lparen_token;
if (type_specifier_list)
if (unsigned candidate = type_specifier_list->firstToken())
return candidate;
if (declarator)
if (unsigned candidate = declarator->firstToken())
return candidate;
if (initializer)
if (unsigned candidate = initializer->firstToken())
return candidate;
if (colon_token)
return colon_token;
if (expression)
if (unsigned candidate = expression->firstToken())
return candidate;
if (rparen_token)
return rparen_token;
if (statement)
if (unsigned candidate = statement->firstToken())
return candidate;
return 0;
}
/** \generated */
unsigned RangeBasedForStatementAST::lastToken() const
{
if (statement)
if (unsigned candidate = statement->lastToken())
return candidate;
if (rparen_token)
return rparen_token + 1;
if (expression)
if (unsigned candidate = expression->lastToken())
return candidate;
if (colon_token)
return colon_token + 1;
if (initializer)
if (unsigned candidate = initializer->lastToken())
return candidate;
if (declarator)
if (unsigned candidate = declarator->lastToken())
return candidate;
if (type_specifier_list)
if (unsigned candidate = type_specifier_list->lastToken())
return candidate;
if (lparen_token)
return lparen_token + 1;
if (for_token)
return for_token + 1;
return 1;
}
......@@ -247,6 +247,7 @@ public:
virtual QtPropertyDeclarationAST *asQtPropertyDeclaration() { return 0; }
virtual QtPropertyDeclarationItemAST *asQtPropertyDeclarationItem() { return 0; }
virtual QualifiedNameAST *asQualifiedName() { return 0; }
virtual RangeBasedForStatementAST *asRangeBasedForStatement() { return 0; }
virtual ReferenceAST *asReference() { return 0; }
virtual ReturnStatementAST *asReturnStatement() { return 0; }
virtual SimpleDeclarationAST *asSimpleDeclaration() { return 0; }
......@@ -1906,6 +1907,50 @@ protected:
virtual bool match0(AST *, ASTMatcher *);
};
class CPLUSPLUS_EXPORT RangeBasedForStatementAST : public StatementAST
{
public:
unsigned for_token;
unsigned lparen_token;
// declaration
SpecifierListAST *type_specifier_list;
DeclaratorAST *declarator;
// or an expression
ExpressionAST *initializer;
unsigned colon_token;
ExpressionAST *expression;
unsigned rparen_token;
StatementAST *statement;
public: // annotations
Block *symbol;
public:
RangeBasedForStatementAST()
: for_token(0)
, lparen_token(0)
, type_specifier_list(0)
, declarator(0)
, initializer(0)
, colon_token(0)
, expression(0)
, rparen_token(0)
, statement(0)
, symbol(0)
{}
virtual RangeBasedForStatementAST *asRangeBasedForStatement() { return this; }
virtual unsigned firstToken() const;
virtual unsigned lastToken() const;
virtual RangeBasedForStatementAST *clone(MemoryPool *pool) const;
protected:
virtual void accept0(ASTVisitor *visitor);
virtual bool match0(AST *, ASTMatcher *);
};
class CPLUSPLUS_EXPORT ForStatementAST: public StatementAST
{
public:
......
......@@ -669,6 +669,27 @@ ForeachStatementAST *ForeachStatementAST::clone(MemoryPool *pool) const
return ast;
}
RangeBasedForStatementAST *RangeBasedForStatementAST::clone(MemoryPool *pool) const
{
RangeBasedForStatementAST *ast = new (pool) RangeBasedForStatementAST;
ast->for_token = for_token;
ast->lparen_token = lparen_token;
for (SpecifierListAST *iter = type_specifier_list, **ast_iter = &ast->type_specifier_list;
iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
*ast_iter = new (pool) SpecifierListAST((iter->value) ? iter->value->clone(pool) : 0);
if (declarator)
ast->declarator = declarator->clone(pool);
if (initializer)
ast->initializer = initializer->clone(pool);
ast->colon_token = colon_token;
if (expression)
ast->expression = expression->clone(pool);
ast->rparen_token = rparen_token;
if (statement)
ast->statement = statement->clone(pool);
return ast;
}
ForStatementAST *ForStatementAST::clone(MemoryPool *pool) const
{
ForStatementAST *ast = new (pool) ForStatementAST;
......
......@@ -456,6 +456,14 @@ bool ForeachStatementAST::match0(AST *pattern, ASTMatcher *matcher)
return false;
}
bool RangeBasedForStatementAST::match0(AST *pattern, ASTMatcher *matcher)
{
if (RangeBasedForStatementAST *_other = pattern->asRangeBasedForStatement())
return matcher->match(this, _other);
return false;
}
bool ForStatementAST::match0(AST *pattern, ASTMatcher *matcher)
{
if (ForStatementAST *_other = pattern->asForStatement())
......
......@@ -1131,6 +1131,47 @@ bool ASTMatcher::match(ForeachStatementAST *node, ForeachStatementAST *pattern)
return true;
}
bool ASTMatcher::match(RangeBasedForStatementAST *node, RangeBasedForStatementAST *pattern)
{
(void) node;
(void) pattern;
pattern->for_token = node->for_token;
pattern->lparen_token = node->lparen_token;
if (! pattern->type_specifier_list)
pattern->type_specifier_list = node->type_specifier_list;
else if (! AST::match(node->type_specifier_list, pattern->type_specifier_list, this))
return false;
if (! pattern->declarator)
pattern->declarator = node->declarator;
else if (! AST::match(node->declarator, pattern->declarator, this))
return false;
if (! pattern->initializer)
pattern->initializer = node->initializer;
else if (! AST::match(node->initializer, pattern->initializer, this))
return false;
pattern->colon_token = node->colon_token;
if (! pattern->expression)
pattern->expression = node->expression;
else if (! AST::match(node->expression, pattern->expression, this))
return false;
pattern->rparen_token = node->rparen_token;
if (! pattern->statement)
pattern->statement = node->statement;
else if (! AST::match(node->statement, pattern->statement, this))
return false;
return true;
}
bool ASTMatcher::match(ForStatementAST *node, ForStatementAST *pattern)
{
(void) node;
......
......@@ -146,6 +146,7 @@ public:
virtual bool match(QtPropertyDeclarationAST *node, QtPropertyDeclarationAST *pattern);
virtual bool match(QtPropertyDeclarationItemAST *node, QtPropertyDeclarationItemAST *pattern);
virtual bool match(QualifiedNameAST *node, QualifiedNameAST *pattern);
virtual bool match(RangeBasedForStatementAST *node, RangeBasedForStatementAST *pattern);
virtual bool match(ReferenceAST *node, ReferenceAST *pattern);
virtual bool match(ReturnStatementAST *node, ReturnStatementAST *pattern);
virtual bool match(SimpleDeclarationAST *node, SimpleDeclarationAST *pattern);
......
......@@ -447,6 +447,17 @@ public:
return __ast;
}
RangeBasedForStatementAST *RangeBasedForStatement(SpecifierListAST *type_specifier_list = 0, DeclaratorAST *declarator = 0, ExpressionAST *initializer = 0, ExpressionAST *expression = 0, StatementAST *statement = 0)
{
RangeBasedForStatementAST *__ast = new (&pool) RangeBasedForStatementAST;
__ast->type_specifier_list = type_specifier_list;
__ast->declarator = declarator;
__ast->initializer = initializer;
__ast->expression = expression;
__ast->statement = statement;
return __ast;
}
ForStatementAST *ForStatement(StatementAST *initializer = 0, ExpressionAST *condition = 0, ExpressionAST *expression = 0, StatementAST *statement = 0)
{
ForStatementAST *__ast = new (&pool) ForStatementAST;
......
......@@ -488,6 +488,18 @@ void ForeachStatementAST::accept0(ASTVisitor *visitor)
visitor->endVisit(this);
}
void RangeBasedForStatementAST::accept0(ASTVisitor *visitor)
{
if (visitor->visit(this)) {
accept(type_specifier_list, visitor);
accept(declarator, visitor);
accept(initializer, visitor);
accept(expression, visitor);
accept(statement, visitor);
}
visitor->endVisit(this);
}
void ForStatementAST::accept0(ASTVisitor *visitor)
{
if (visitor->visit(this)) {
......
......@@ -90,5 +90,3 @@ void ASTVisitor::getTokenStartPosition(unsigned index, unsigned *line, unsigned
void ASTVisitor::getTokenEndPosition(unsigned index, unsigned *line, unsigned *column) const
{ getPosition(tokenAt(index).end(), line, column); }
......@@ -188,6 +188,7 @@ public:
virtual bool visit(QtPropertyDeclarationAST *) { return true; }
virtual bool visit(QtPropertyDeclarationItemAST *) { return true; }
virtual bool visit(QualifiedNameAST *) { return true; }
virtual bool visit(RangeBasedForStatementAST *) { return true; }
virtual bool visit(ReferenceAST *) { return true; }
virtual bool visit(ReturnStatementAST *) { return true; }
virtual bool visit(SimpleDeclarationAST *) { return true; }
......@@ -331,6 +332,7 @@ public:
virtual void endVisit(QtPropertyDeclarationAST *) {}
virtual void endVisit(QtPropertyDeclarationItemAST *) {}
virtual void endVisit(QualifiedNameAST *) {}
virtual void endVisit(RangeBasedForStatementAST *) {}
virtual void endVisit(ReferenceAST *) {}
virtual void endVisit(ReturnStatementAST *) {}
virtual void endVisit(SimpleDeclarationAST *) {}
......
......@@ -154,6 +154,7 @@ class QtPrivateSlotAST;
class QtPropertyDeclarationAST;
class QtPropertyDeclarationItemAST;
class QualifiedNameAST;
class RangeBasedForStatementAST;
class ReferenceAST;
class ReturnStatementAST;
class SimpleDeclarationAST;
......
......@@ -1282,6 +1282,56 @@ bool Bind::visit(ForeachStatementAST *ast)
return false;
}
bool Bind::visit(RangeBasedForStatementAST *ast)
{
Block *block = control()->newBlock(ast->firstToken());
const unsigned startScopeToken = ast->lparen_token ? ast->lparen_token : ast->firstToken();
block->setStartOffset(tokenAt(startScopeToken).end());
block->setEndOffset(tokenAt(ast->lastToken()).begin());
_scope->addMember(block);
ast->symbol = block;
Scope *previousScope = switchScope(block);
FullySpecifiedType type;
for (SpecifierListAST *it = ast->type_specifier_list; it; it = it->next) {
type = this->specifier(it->value, type);
}
DeclaratorIdAST *declaratorId = 0;
type = this->declarator(ast->declarator, type, &declaratorId);
const StringLiteral *initializer = 0;
if (type.isAuto() && translationUnit()->cxx0xEnabled()) {
ExpressionTy exprType = this->expression(ast->expression);
ArrayType* arrayType = 0;
arrayType = exprType->asArrayType();
if (arrayType != 0)
type = arrayType->elementType();
else if (ast->expression != 0) {
unsigned startOfExpression = ast->expression->firstToken();
unsigned endOfExpression = ast->expression->lastToken();
const StringLiteral *sl = asStringLiteral(startOfExpression, endOfExpression);
const std::string buff = std::string("*") + sl->chars() + ".begin()";
initializer = control()->stringLiteral(buff.c_str(), buff.size());
}
}
if (declaratorId && declaratorId->name) {
unsigned sourceLocation = location(declaratorId->name, ast->firstToken());
Declaration *decl = control()->newDeclaration(sourceLocation, declaratorId->name->name);
decl->setType(type);
decl->setInitializer(initializer);
block->addMember(decl);
}
/*ExpressionTy initializer =*/ this->expression(ast->initializer);
/*ExpressionTy expression =*/ this->expression(ast->expression);
this->statement(ast->statement);
(void) switchScope(previousScope);
return false;
}
bool Bind::visit(ForStatementAST *ast)
{
Block *block = control()->newBlock(ast->firstToken());
......
......@@ -152,6 +152,7 @@ protected:
virtual bool visit(ExpressionOrDeclarationStatementAST *ast);
virtual bool visit(ExpressionStatementAST *ast);
virtual bool visit(ForeachStatementAST *ast);
virtual bool visit(RangeBasedForStatementAST *ast);
virtual bool visit(ForStatementAST *ast);
virtual bool visit(IfStatementAST *ast);
virtual bool visit(LabeledStatementAST *ast);
......
......@@ -3230,6 +3230,32 @@ bool Parser::parseForStatement(StatementAST *&node)
rewind(startOfTypeSpecifier);
}
if (cxx0xEnabled()) {
RangeBasedForStatementAST *ast = new (_pool) RangeBasedForStatementAST;
ast->for_token = for_token;
ast->lparen_token = lparen_token;
if (parseTypeSpecifier(ast->type_specifier_list))
parseDeclarator(ast->declarator, ast->type_specifier_list);
if ((ast->type_specifier_list || ast->declarator) && LA() == T_COLON) {
ast->colon_token = consumeToken();
blockErrors(blocked);
parseExpression(ast->expression);
match(T_RPAREN, &ast->rparen_token);
parseStatement(ast->statement);
// We need both type specifier and declarator for C++11 range-based for
if (!ast->type_specifier_list || !ast->declarator)
error(for_token, "expected declaration with type specifier");
node = ast;
return true;
}
rewind(startOfTypeSpecifier);
}
blockErrors(blocked);
// Normal C/C++ for-statement parsing
......@@ -6108,4 +6134,3 @@ void Parser::fatal(unsigned index, const char *format, ...)
va_end(ap);
va_end(args);
}
......@@ -1050,6 +1050,23 @@ bool FindUsages::visit(ForeachStatementAST *ast)
return false;
}
bool FindUsages::visit(RangeBasedForStatementAST *ast)
{
Scope *previousScope = switchScope(ast->symbol);
for (SpecifierListAST *it = ast->type_specifier_list; it; it = it->next) {
this->specifier(it->value);
}
this->declarator(ast->declarator);
this->expression(ast->initializer);
// unsigned comma_token = ast->comma_token;
this->expression(ast->expression);
// unsigned rparen_token = ast->rparen_token;
this->statement(ast->statement);
// Block *symbol = ast->symbol;
(void) switchScope(previousScope);
return false;
}
bool FindUsages::visit(ForStatementAST *ast)
{
// unsigned for_token = ast->for_token;
......@@ -2215,5 +2232,3 @@ bool FindUsages::visit(ArrayDeclaratorAST *ast)
// unsigned rbracket_token = ast->rbracket_token;
return false;
}
......@@ -171,6 +171,7 @@ protected:
virtual bool visit(ExpressionOrDeclarationStatementAST *ast);
virtual bool visit(ExpressionStatementAST *ast);
virtual bool visit(ForeachStatementAST *ast);
virtual bool visit(RangeBasedForStatementAST *ast);
virtual bool visit(ForStatementAST *ast);
virtual bool visit(IfStatementAST *ast);
virtual bool visit(LabeledStatementAST *ast);
......
......@@ -144,6 +144,15 @@ bool FindCdbBreakpoint::visit(ForeachStatementAST *ast)
return false;
}
bool FindCdbBreakpoint::visit(RangeBasedForStatementAST *ast)
{
if (m_initialLine <= endLine(ast->rparen_token))
foundLine(ast->rparen_token);
accept(ast->statement);
return false;
}
bool FindCdbBreakpoint::visit(ForStatementAST *ast)
{
if (m_initialLine <= endLine(ast->rparen_token))
......
......@@ -78,6 +78,7 @@ protected:
bool visit(DoStatementAST *ast);
bool visit(ExpressionStatementAST *ast);
bool visit(ForeachStatementAST *ast);
bool visit(RangeBasedForStatementAST *ast);
bool visit(ForStatementAST *ast);
bool visit(IfStatementAST *ast);
bool visit(LabeledStatementAST *ast);
......
......@@ -639,6 +639,12 @@ public:
return false;
}
bool visit(RangeBasedForStatementAST *stmt)
{
statement(stmt->statement);
return false;
}
bool visit(ForStatementAST *stmt)
{
statement(stmt->initializer);
......
......@@ -407,6 +407,10 @@ Scope *CheckSymbols::enclosingScope() const
if (foreachStmt->symbol)
return foreachStmt->symbol;
} else if (RangeBasedForStatementAST *rangeBasedForStmt = ast->asRangeBasedForStatement()) {
if (rangeBasedForStmt->symbol)
return rangeBasedForStmt->symbol;
} else if (SwitchStatementAST *switchStmt = ast->asSwitchStatement()) {
if (switchStmt->symbol)
return switchStmt->symbol;
......
......@@ -253,6 +253,19 @@ protected:
_scopeStack.removeLast();
}
virtual bool visit(RangeBasedForStatementAST *ast)
{
if (ast->symbol)
enterScope(ast->symbol);
return true;
}
virtual void endVisit(RangeBasedForStatementAST *ast)
{
if (ast->symbol)
_scopeStack.removeLast();
}
virtual bool visit(SwitchStatementAST *ast)
{
if (ast->symbol)
......
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