]> granicus.if.org Git - clang/commitdiff
Patch to parse/build AST ObjC2's foreach statement.
authorFariborz Jahanian <fjahanian@apple.com>
Thu, 3 Jan 2008 17:55:25 +0000 (17:55 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Thu, 3 Jan 2008 17:55:25 +0000 (17:55 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@45539 91177308-0d34-0410-b5e6-96231b3b80d8

Parse/ParseDecl.cpp
Parse/ParseObjc.cpp
Parse/ParseStmt.cpp
Sema/Sema.h
Sema/SemaStmt.cpp
include/clang/Parse/Action.h

index b45ef47554a2dc8b99b8e11d344acb6ed9f39064..a2a3f3e7c0d8582ba00bb3aea66fc65bcccfc532 100644 (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);
index e661e8775b2c47d8fa97e80f119683a3fd3d6fdb..c17e35e6f4987eb9cfdfb096c6a309a36004faa2 100644 (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;
   }
index 4933ac72c6b436d720753d3cdf5a6c5f037527df..762e499d81274f8ed80dadc6327f22f196c70fff 100644 (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
index 5610b3a9e402520b58873ac6dec9b57030cc5729..7faac134582fef1e0739fbfc18e94bb9b5b3e6cd 100644 (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);
index f83ff4b32de761a14a39f27c7ed2a16f51f7b2fd..cbb01bdb3c5ba454b0c7cbe6b5bdc57f34d98e1c 100644 (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,
index b711ec7401f1f36e82aa37fbb8c21f280950fa89..bfd66243895c45c137ded21352bba6fb88f91c39 100644 (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) {