From: Steve Naroff Date: Mon, 20 Aug 2007 21:31:48 +0000 (+0000) Subject: Start parsing ObjC classes/categories! X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dac269b65eed82182fc3e96566dedd6562dfe11e;p=clang Start parsing ObjC classes/categories! 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 --- diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp index 00b606ac1a..192f19990a 100644 --- a/Parse/ParseObjc.cpp +++ b/Parse/ParseObjc.cpp @@ -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 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 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() { diff --git a/Parse/Parser.cpp b/Parse/Parser.cpp index 7ff0609784..34c9ca6ca3 100644 --- a/Parse/Parser.cpp +++ b/Parse/Parser.cpp @@ -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); diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 9d5d0e0c41..979128057d 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -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 //===----------------------------------------------------------------------===// diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 522f6e0381..eb0b319e07 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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();