Patch to parse/build AST ObjC2's foreach statement.

llvm-svn: 45539
This commit is contained in:
Fariborz Jahanian 2008-01-03 17:55:25 +00:00
parent 9b92e93d36
commit 732b8c2dc5
6 changed files with 102 additions and 33 deletions

View File

@ -296,7 +296,9 @@ ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
ConsumeToken();
return Actions.FinalizeDeclaratorGroup(CurScope, LastDeclInGroup);
}
if (D.getContext() == Declarator::ForContext && isObjCForCollectionInKW()) {
return Actions.FinalizeDeclaratorGroup(CurScope, LastDeclInGroup);
}
Diag(Tok, diag::err_parse_error);
// Skip to end of block or statement
SkipUntil(tok::r_brace, true, true);

View File

@ -494,7 +494,10 @@ bool Parser::isObjCPropertyAttribute() {
/// objc-for-collection-in: 'in'
///
bool Parser::isObjCForCollectionInKW() {
if (Tok.is(tok::identifier)) {
// FIXME: May have to do additional look-ahead to only allow for
// valid tokens following an 'in'; such as an identifier, unary operators,
// '[' etc.
if (getLang().ObjC2 && Tok.is(tok::identifier)) {
const IdentifierInfo *II = Tok.getIdentifierInfo();
return II == ObjCForCollectionInKW;
}

View File

@ -721,6 +721,8 @@ Parser::StmtResult Parser::ParseDoStatement() {
/// for-statement: [C99 6.8.5.3]
/// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
/// [OBJC2] 'for' '(' declaration 'in' expr ')' statement
/// [OBJC2] 'for' '(' expr 'in' expr ')' statement
Parser::StmtResult Parser::ParseForStatement() {
assert(Tok.is(tok::kw_for) && "Not a for stmt!");
SourceLocation ForLoc = ConsumeToken(); // eat the 'for'.
@ -744,6 +746,7 @@ Parser::StmtResult Parser::ParseForStatement() {
StmtTy *FirstPart = 0;
ExprTy *SecondPart = 0;
StmtTy *ThirdPart = 0;
bool foreach = false;
// Parse the first part of the for specifier.
if (Tok.is(tok::semi)) { // for (;
@ -756,6 +759,12 @@ Parser::StmtResult Parser::ParseForStatement() {
DeclTy *aBlockVarDecl = ParseDeclaration(Declarator::ForContext);
StmtResult stmtResult = Actions.ActOnDeclStmt(aBlockVarDecl);
FirstPart = stmtResult.isInvalid ? 0 : stmtResult.Val;
if ((foreach = isObjCForCollectionInKW())) {
ConsumeToken(); // consume 'in'
Value = ParseExpression();
if (!Value.isInvalid)
SecondPart = Value.Val;
}
} else {
Value = ParseExpression();
@ -768,43 +777,50 @@ Parser::StmtResult Parser::ParseForStatement() {
if (Tok.is(tok::semi)) {
ConsumeToken();
} else {
}
else if ((foreach = isObjCForCollectionInKW())) {
ConsumeToken(); // consume 'in'
Value = ParseExpression();
if (!Value.isInvalid)
SecondPart = Value.Val;
}
else {
if (!Value.isInvalid) Diag(Tok, diag::err_expected_semi_for);
SkipUntil(tok::semi);
}
}
if (!foreach) {
// Parse the second part of the for specifier.
if (Tok.is(tok::semi)) { // for (...;;
// no second part.
Value = ExprResult();
} else {
Value = ParseExpression();
if (!Value.isInvalid)
SecondPart = Value.Val;
}
// Parse the second part of the for specifier.
if (Tok.is(tok::semi)) { // for (...;;
// no second part.
Value = ExprResult();
} else {
Value = ParseExpression();
if (!Value.isInvalid)
SecondPart = Value.Val;
}
if (Tok.is(tok::semi)) {
ConsumeToken();
} else {
if (!Value.isInvalid) Diag(Tok, diag::err_expected_semi_for);
SkipUntil(tok::semi);
}
if (Tok.is(tok::semi)) {
ConsumeToken();
} else {
if (!Value.isInvalid) Diag(Tok, diag::err_expected_semi_for);
SkipUntil(tok::semi);
}
// Parse the third part of the for specifier.
if (Tok.is(tok::r_paren)) { // for (...;...;)
// no third part.
Value = ExprResult();
} else {
Value = ParseExpression();
if (!Value.isInvalid) {
// Turn the expression into a stmt.
StmtResult R = Actions.ActOnExprStmt(Value.Val);
if (!R.isInvalid)
ThirdPart = R.Val;
// Parse the third part of the for specifier.
if (Tok.is(tok::r_paren)) { // for (...;...;)
// no third part.
Value = ExprResult();
} else {
Value = ParseExpression();
if (!Value.isInvalid) {
// Turn the expression into a stmt.
StmtResult R = Actions.ActOnExprStmt(Value.Val);
if (!R.isInvalid)
ThirdPart = R.Val;
}
}
}
// Match the ')'.
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
@ -826,8 +842,12 @@ Parser::StmtResult Parser::ParseForStatement() {
if (Body.isInvalid)
return Body;
return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart, SecondPart,
ThirdPart, RParenLoc, Body.Val);
return !foreach ? Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart,
SecondPart, ThirdPart, RParenLoc,
Body.Val)
: Actions.ActOnObjcForCollectionStmt(ForLoc, LParenLoc,
FirstPart, SecondPart,
RParenLoc, Body.Val);
}
/// ParseGotoStatement

View File

@ -325,6 +325,11 @@ public:
SourceLocation LParenLoc,
StmtTy *First, ExprTy *Second, ExprTy *Third,
SourceLocation RParenLoc, StmtTy *Body);
virtual StmtResult ActOnObjcForCollectionStmt(SourceLocation ForColLoc,
SourceLocation LParenLoc,
StmtTy *First, ExprTy *Second,
SourceLocation RParenLoc, StmtTy *Body);
virtual StmtResult ActOnGotoStmt(SourceLocation GotoLoc,
SourceLocation LabelLoc,
IdentifierInfo *LabelII);

View File

@ -530,6 +530,39 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
return new ForStmt(First, Second, Third, Body, ForLoc);
}
Action::StmtResult
Sema::ActOnObjcForCollectionStmt(SourceLocation ForColLoc,
SourceLocation LParenLoc,
StmtTy *first, ExprTy *second,
SourceLocation RParenLoc, StmtTy *body) {
Stmt *First = static_cast<Stmt*>(first);
Expr *Second = static_cast<Expr*>(second);
Stmt *Body = static_cast<Stmt*>(body);
if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) {
// C99 6.8.5p3: The declaration part of a 'for' statement shall only declare
// identifiers for objects having storage class 'auto' or 'register'.
for (ScopedDecl *D = DS->getDecl(); D; D = D->getNextDeclarator()) {
BlockVarDecl *BVD = dyn_cast<BlockVarDecl>(D);
if (BVD && !BVD->hasLocalStorage())
BVD = 0;
if (BVD == 0)
Diag(dyn_cast<ScopedDecl>(D)->getLocation(),
diag::err_non_variable_decl_in_for);
// FIXME: mark decl erroneous!
}
}
if (Second) {
DefaultFunctionArrayConversion(Second);
QualType SecondType = Second->getType();
#if 0
if (!SecondType->isScalarType()) // C99 6.8.5p2
return Diag(ForColLoc, diag::err_typecheck_statement_requires_scalar,
SecondType.getAsString(), Second->getSourceRange());
#endif
}
return new ObjcForCollectionStmt(First, Second, Body, ForColLoc);
}
Action::StmtResult
Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,

View File

@ -265,6 +265,12 @@ public:
SourceLocation RParenLoc, StmtTy *Body) {
return 0;
}
virtual StmtResult ActOnObjcForCollectionStmt(SourceLocation ForColLoc,
SourceLocation LParenLoc,
StmtTy *First, ExprTy *Second,
SourceLocation RParenLoc, StmtTy *Body) {
return 0;
}
virtual StmtResult ActOnGotoStmt(SourceLocation GotoLoc,
SourceLocation LabelLoc,
IdentifierInfo *LabelII) {