]> granicus.if.org Git - clang/commitdiff
Start parsing ObjC classes/categories!
authorSteve Naroff <snaroff@apple.com>
Mon, 20 Aug 2007 21:31:48 +0000 (21:31 +0000)
committerSteve Naroff <snaroff@apple.com>
Mon, 20 Aug 2007 21:31:48 +0000 (21:31 +0000)
Next step, refactor Parser::ParseStructUnionBody() so that struct declarations can
be shared with Objective-C (for declaring instance variables).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41200 91177308-0d34-0410-b5e6-96231b3b80d8

Parse/ParseObjc.cpp
Parse/Parser.cpp
include/clang/Basic/DiagnosticKinds.def
include/clang/Parse/Parser.h

index 00b606ac1a5da2e1abd69e0d9df27154d88c2107..192f19990acc224287ca80183f4d11e19ed4328b 100644 (file)
@@ -25,7 +25,7 @@ using namespace clang;
 /// [OBJC]  objc-protocol-definition   [TODO]
 /// [OBJC]  objc-method-definition     [TODO]
 /// [OBJC]  '@' 'end'                  [TODO]
-void Parser::ParseObjCAtDirectives() {
+Parser::DeclTy *Parser::ParseObjCAtDirectives() {
   SourceLocation AtLoc = ConsumeToken(); // the "@"
   
   IdentifierInfo *II = Tok.getIdentifierInfo();
@@ -33,7 +33,7 @@ void Parser::ParseObjCAtDirectives() {
     case tok::objc_class:
       return ParseObjCAtClassDeclaration(AtLoc);
     case tok::objc_interface:
-      return ParseObjCAtInterfaceDeclaration();
+      return ParseObjCAtInterfaceDeclaration(AtLoc);
     case tok::objc_protocol:
       return ParseObjCAtProtocolDeclaration();
     case tok::objc_implementation:
@@ -45,6 +45,7 @@ void Parser::ParseObjCAtDirectives() {
     default:
       Diag(AtLoc, diag::err_unexpected_at);
       SkipUntil(tok::semi);
+      return 0;
   }
 }
 
@@ -52,7 +53,7 @@ void Parser::ParseObjCAtDirectives() {
 /// objc-class-declaration: 
 ///    '@' 'class' identifier-list ';'
 ///  
-void Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
+Parser::DeclTy *Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
   ConsumeToken(); // the identifier "class"
   llvm::SmallVector<IdentifierInfo *, 8> ClassNames;
   
@@ -60,7 +61,7 @@ void Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
     if (Tok.getKind() != tok::identifier) {
       Diag(Tok, diag::err_expected_ident);
       SkipUntil(tok::semi);
-      return;
+      return 0;
     }
     
     ClassNames.push_back(Tok.getIdentifierInfo());
@@ -74,26 +75,232 @@ void Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
   
   // Consume the ';'.
   if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
-    return;
+    return 0;
   
-  Actions.ParsedObjcClassDeclaration(CurScope,
-                                     &ClassNames[0], ClassNames.size());
+  return Actions.ParsedObjcClassDeclaration(CurScope,
+                                            &ClassNames[0], ClassNames.size());
 }
 
-void Parser::ParseObjCAtInterfaceDeclaration() {
+///
+///   objc-interface:
+///     objc-class-interface-attributes[opt] objc-class-interface
+///     objc-category-interface
+///
+///   objc-class-interface:
+///     '@' 'interface' identifier objc-superclass[opt] 
+///       objc-protocol-refs[opt]
+///       objc-class-instance-variables[opt] 
+///       objc-interface-decl-list
+///     @end
+///
+///   objc-category-interface:
+///     '@' 'interface' identifier '(' identifier[opt] ')' 
+///       objc-protocol-refs[opt]
+///       objc-interface-decl-list
+///     @end
+///
+///   objc-superclass:
+///     ':' identifier
+///
+///   objc-class-interface-attributes:
+///     __attribute__((visibility("default")))
+///     __attribute__((visibility("hidden")))
+///     __attribute__((deprecated))
+///     __attribute__((unavailable))
+///     __attribute__((objc_exception)) - used by NSException on 64-bit
+///
+Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration(
+  SourceLocation atLoc, AttributeList *attrList) {
+  assert(Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_interface &&
+         "ParseObjCAtInterfaceDeclaration(): Expected @interface");
+  ConsumeToken(); // the "interface" identifier
+  
+  if (Tok.getKind() != tok::identifier) {
+    Diag(Tok, diag::err_expected_ident); // missing class or category name.
+    return 0;
+  }
+  // We have a class or category name - consume it.
+  IdentifierInfo *nameId = Tok.getIdentifierInfo();
+  SourceLocation nameLoc = ConsumeToken();
+  
+  if (Tok.getKind() == tok::l_paren) { // we have a category
+    SourceLocation lparenLoc = ConsumeParen();
+    SourceLocation categoryLoc, rparenLoc;
+    IdentifierInfo *categoryId = 0;
+    
+    // OBJC2: The cateogry name is optional (not an error).
+    if (Tok.getKind() == tok::identifier) {
+      categoryId = Tok.getIdentifierInfo();
+      categoryLoc = ConsumeToken();
+    }
+    if (Tok.getKind() != tok::r_paren) {
+      Diag(Tok, diag::err_expected_rparen);
+      SkipUntil(tok::r_paren, false); // don't stop at ';'
+      return 0;
+    }
+    rparenLoc = ConsumeParen();
+    // Next, we need to check for any protocol references.
+    if (Tok.getKind() == tok::less) {
+      if (ParseObjCProtocolReferences())
+        return 0;
+    }
+    if (attrList) // categories don't support attributes.
+      Diag(Tok, diag::err_objc_no_attributes_on_category);
+    
+    //ParseObjCInterfaceDeclList();
+
+    if (Tok.getKind() != tok::at) { // check for @end
+      Diag(Tok, diag::err_objc_missing_end);
+      return 0;
+    }
+    SourceLocation atEndLoc = ConsumeToken(); // eat the @ sign
+    if (Tok.getIdentifierInfo()->getObjCKeywordID() != tok::objc_end) {
+      Diag(Tok, diag::err_objc_missing_end);
+      return 0;
+    }
+    ConsumeToken(); // the "end" identifier
+    return 0;
+  }
+  // Parse a class interface.
+  IdentifierInfo *superClassId = 0;
+  SourceLocation superClassLoc;
+  
+  if (Tok.getKind() == tok::colon) { // a super class is specified.
+    ConsumeToken();
+    if (Tok.getKind() != tok::identifier) {
+      Diag(Tok, diag::err_expected_ident); // missing super class name.
+      return 0;
+    }
+    superClassId = Tok.getIdentifierInfo();
+    superClassLoc = ConsumeToken();
+  }
+  // Next, we need to check for any protocol references.
+  if (Tok.getKind() == tok::less) {
+    if (ParseObjCProtocolReferences())
+      return 0;
+  }
+  if (Tok.getKind() == tok::l_brace)
+    ParseObjCClassInstanceVariables();
+
+  //ParseObjCInterfaceDeclList();
+  
+  if (Tok.getKind() != tok::at) { // check for @end
+    Diag(Tok, diag::err_objc_missing_end);
+    return 0;
+  }
+  SourceLocation atEndLoc = ConsumeToken(); // eat the @ sign
+  if (Tok.getIdentifierInfo()->getObjCKeywordID() != tok::objc_end) {
+    Diag(Tok, diag::err_objc_missing_end);
+    return 0;
+  }
+  ConsumeToken(); // the "end" identifier
+  return 0;
+}
+
+///   objc-interface-decl-list:
+///     empty
+///     objc-interface-decl-list objc-method-proto
+///     objc-interface-decl-list objc-property-decl [OBJC2]
+///     objc-interface-decl-list declaration
+///     objc-interface-decl-list ';'
+///
+void Parser::ParseObjCInterfaceDeclList() {
   assert(0 && "Unimp");
 }
-void Parser::ParseObjCAtProtocolDeclaration() {
+
+///   objc-protocol-refs:
+///     '<' identifier-list '>'
+///
+bool Parser::ParseObjCProtocolReferences() {
+  assert(Tok.getKind() == tok::less && "expected <");
+  
+  ConsumeToken(); // the "<"
+  llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
+  
+  while (1) {
+    if (Tok.getKind() != tok::identifier) {
+      Diag(Tok, diag::err_expected_ident);
+      SkipUntil(tok::greater);
+      return true;
+    }
+    ProtocolRefs.push_back(Tok.getIdentifierInfo());
+    ConsumeToken();
+    
+    if (Tok.getKind() != tok::comma)
+      break;
+    ConsumeToken();
+  }
+  // Consume the '>'.
+  return ExpectAndConsume(tok::greater, diag::err_expected_greater);
+}
+
+///   objc-class-instance-variables:
+///     '{' objc-instance-variable-decl-list[opt] '}'
+///
+///   objc-instance-variable-decl-list:
+///     objc-visibility-spec
+///     objc-instance-variable-decl ';'
+///     ';'
+///     objc-instance-variable-decl-list objc-visibility-spec
+///     objc-instance-variable-decl-list objc-instance-variable-decl ';'
+///     objc-instance-variable-decl-list ';'
+///
+///   objc-visibility-spec:
+///     @private
+///     @protected
+///     @public
+///
+///   objc-instance-variable-decl:
+///     struct-declaration 
+///
+void Parser::ParseObjCClassInstanceVariables() {
   assert(0 && "Unimp");
 }
-void Parser::ParseObjCAtImplementationDeclaration() {
+
+///   objc-protocol-declaration:
+///     objc-protocol-definition
+///     objc-protocol-forward-reference
+///
+///   objc-protocol-definition:
+///     @protocol identifier 
+///       objc-protocol-refs[opt] 
+///       objc-methodprotolist 
+///     @end
+///
+///   objc-protocol-forward-reference:
+///     @protocol identifier-list ';'
+///
+///   "@protocol identifier ;" should be resolved as "@protocol
+///   identifier-list ;": objc-methodprotolist may not start with a
+///   semicolon in the first alternative if objc-protocol-refs are omitted.
+
+Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration() {
+  assert(0 && "Unimp");
+  return 0;
+}
+
+///   objc-implementation:
+///     objc-class-implementation-prologue
+///     objc-category-implementation-prologue
+///
+///   objc-class-implementation-prologue:
+///     @implementation identifier objc-superclass[opt]
+///       objc-class-instance-variables[opt]
+///
+///   objc-category-implementation-prologue:
+///     @implementation identifier ( identifier )
+
+Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration() {
   assert(0 && "Unimp");
+  return 0;
 }
-void Parser::ParseObjCAtEndDeclaration() {
+Parser::DeclTy *Parser::ParseObjCAtEndDeclaration() {
   assert(0 && "Unimp");
+  return 0;
 }
-void Parser::ParseObjCAtAliasDeclaration() {
+Parser::DeclTy *Parser::ParseObjCAtAliasDeclaration() {
   assert(0 && "Unimp");
+  return 0;
 }
 
 void Parser::ParseObjCInstanceMethodDeclaration() {
index 7ff060978469b634e4fe7b58500d68df5f9500d6..34c9ca6ca3e675c45f756552cc9d5fad7bc8f4af 100644 (file)
@@ -370,6 +370,13 @@ Parser::DeclTy *Parser::ParseDeclarationOrFunctionDefinition() {
     return Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
   }
   
+  // OBJC: This grammar hack allows prefix attributes on class interfaces.
+  if (Tok.getKind() == tok::at) {
+    SourceLocation AtLoc = ConsumeToken(); // the "@"
+    if (Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_interface)
+      return ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes()); 
+  }
+  
   // Parse the first declarator.
   Declarator DeclaratorInfo(DS, Declarator::FileContext);
   ParseDeclarator(DeclaratorInfo);
index 9d5d0e0c41a0e9bdaf792a75e133e7a7f25ee61c..979128057d276311eaf9e4725ae014c82e29281c 100644 (file)
@@ -377,6 +377,12 @@ DIAG(err_unexpected_at, ERROR,
 DIAG(err_matching, ERROR,
      "to match this '%0'")
 
+/// Objective-C parser diagnostics
+DIAG(err_objc_no_attributes_on_category, ERROR,
+     "attributes may not be specified on a category")
+DIAG(err_objc_missing_end, ERROR,
+     "missing @end")
+
 //===----------------------------------------------------------------------===//
 // Semantic Analysis
 //===----------------------------------------------------------------------===//
index 522f6e03813fabe18878b8bfba75d05f8bf420d3..eb0b319e078d1e49f50ad761fe0bd7421c5fd9e4 100644 (file)
@@ -254,13 +254,17 @@ private:
   void ParseAsmStringLiteral();
 
   // Objective-C External Declarations 
-  void ParseObjCAtDirectives(); 
-  void ParseObjCAtClassDeclaration(SourceLocation atLoc);
-  void ParseObjCAtInterfaceDeclaration();
-  void ParseObjCAtProtocolDeclaration();
-  void ParseObjCAtImplementationDeclaration();
-  void ParseObjCAtEndDeclaration();
-  void ParseObjCAtAliasDeclaration();
+  DeclTy *ParseObjCAtDirectives(); 
+  DeclTy *ParseObjCAtClassDeclaration(SourceLocation atLoc);
+  DeclTy *ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, 
+                                          AttributeList *prefixAttrs = 0);
+  void ParseObjCClassInstanceVariables();
+  bool ParseObjCProtocolReferences();
+  void ParseObjCInterfaceDeclList();
+  DeclTy *ParseObjCAtProtocolDeclaration();
+  DeclTy *ParseObjCAtImplementationDeclaration();
+  DeclTy *ParseObjCAtEndDeclaration();
+  DeclTy *ParseObjCAtAliasDeclaration();
   
   void ParseObjCInstanceMethodDeclaration();
   void ParseObjCClassMethodDeclaration();