From f28b264437053fb0deacc9ba02b18a0966f7290a Mon Sep 17 00:00:00 2001 From: Steve Naroff Date: Wed, 5 Sep 2007 23:30:30 +0000 Subject: [PATCH] Start implementing Actions interface for ObjC classes, instance variables, and methods. Lot's of small changes to the parser. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41732 91177308-0d34-0410-b5e6-96231b3b80d8 --- Parse/ParseDecl.cpp | 6 +- Parse/ParseObjc.cpp | 115 ++++++++++++++++++++++---------- clang.xcodeproj/project.pbxproj | 2 +- include/clang/Parse/Action.h | 29 ++++++++ include/clang/Parse/DeclSpec.h | 17 +++++ include/clang/Parse/Parser.h | 14 ++-- 6 files changed, 137 insertions(+), 46 deletions(-) diff --git a/Parse/ParseDecl.cpp b/Parse/ParseDecl.cpp index 1db426a93f..dc9edc332c 100644 --- a/Parse/ParseDecl.cpp +++ b/Parse/ParseDecl.cpp @@ -406,8 +406,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { else { // FIXME: restrict this to "id" and ObjC classnames. DS.Range.setEnd(Tok.getLocation()); ConsumeToken(); // The identifier - if (Tok.getKind() == tok::less) - ParseObjCProtocolReferences(); + if (Tok.getKind() == tok::less) { + llvm::SmallVector ProtocolRefs; + ParseObjCProtocolReferences(ProtocolRefs); + } continue; } } diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp index 21f59e32b7..39772a3d6a 100644 --- a/Parse/ParseObjc.cpp +++ b/Parse/ParseObjc.cpp @@ -147,13 +147,15 @@ Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration( rparenLoc = ConsumeParen(); // Next, we need to check for any protocol references. if (Tok.getKind() == tok::less) { - if (ParseObjCProtocolReferences()) + llvm::SmallVector ProtocolRefs; + if (ParseObjCProtocolReferences(ProtocolRefs)) return 0; } if (attrList) // categories don't support attributes. Diag(Tok, diag::err_objc_no_attributes_on_category); - ParseObjCInterfaceDeclList(0/*FIXME*/); + llvm::SmallVector MethodDecls; + ParseObjCInterfaceDeclList(0/*FIXME*/, MethodDecls); // The @ sign was already consumed by ParseObjCInterfaceDeclList(). if (Tok.isObjCAtKeyword(tok::objc_end)) { @@ -182,15 +184,21 @@ Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration( superClassLoc = ConsumeToken(); } // Next, we need to check for any protocol references. + llvm::SmallVector ProtocolRefs; if (Tok.getKind() == tok::less) { - if (ParseObjCProtocolReferences()) + if (ParseObjCProtocolReferences(ProtocolRefs)) return 0; } - // FIXME: add Actions.StartObjCClassInterface(nameId, superClassId, ...) + DeclTy *ClsType = Actions.ObjcStartClassInterface(atLoc, nameId, nameLoc, + superClassId, superClassLoc, &ProtocolRefs[0], + ProtocolRefs.size(), attrList); + + llvm::SmallVector IvarDecls; if (Tok.getKind() == tok::l_brace) - ParseObjCClassInstanceVariables(0/*FIXME*/); + ParseObjCClassInstanceVariables(ClsType, IvarDecls); - ParseObjCInterfaceDeclList(0/*FIXME*/); + llvm::SmallVector MethodDecls; + ParseObjCInterfaceDeclList(ClsType, MethodDecls); // The @ sign was already consumed by ParseObjCInterfaceDeclList(). if (Tok.isObjCAtKeyword(tok::objc_end)) { @@ -213,7 +221,9 @@ Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration( /// @required /// @optional /// -void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl) { +void Parser::ParseObjCInterfaceDeclList( + DeclTy *interfaceDecl, llvm::SmallVectorImpl &MethodDecls) { + DeclTy *IDecl = 0; while (1) { if (Tok.getKind() == tok::at) { SourceLocation AtLoc = ConsumeToken(); // the "@" @@ -236,17 +246,20 @@ void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl) { } } if (Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) { - ParseObjCMethodPrototype(true); + IDecl = ParseObjCMethodPrototype(true); + MethodDecls.push_back(IDecl); continue; } if (Tok.getKind() == tok::semi) ConsumeToken(); else if (Tok.getKind() == tok::eof) return; - else + else { // FIXME: as the name implies, this rule allows function definitions. // We could pass a flag or check for functions during semantic analysis. - ParseDeclarationOrFunctionDefinition(); + IDecl = ParseDeclarationOrFunctionDefinition(); + MethodDecls.push_back(IDecl); + } } } @@ -353,7 +366,7 @@ void Parser::ParseObjCPropertyDecl(DeclTy *interfaceDecl) { /// objc-method-attributes: [OBJC2] /// __attribute__((deprecated)) /// -void Parser::ParseObjCMethodPrototype(bool decl) { +Parser::DeclTy *Parser::ParseObjCMethodPrototype(bool decl) { assert((Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) && "expected +/-"); @@ -361,15 +374,12 @@ void Parser::ParseObjCMethodPrototype(bool decl) { SourceLocation methodLoc = ConsumeToken(); // FIXME: deal with "context sensitive" protocol qualifiers in prototypes - ParseObjCMethodDecl(methodType, methodLoc); + DeclTy *MDecl = ParseObjCMethodDecl(methodType, methodLoc); - // If attributes exist after the method, parse them. - if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) - ParseAttributes(); - if (decl) // Consume the ';'. ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "method proto"); + return MDecl; } /// objc-selector: @@ -425,24 +435,26 @@ bool Parser::isObjCPropertyAttribute() { /// objc-type-qualifier /// objc-type-qualifiers objc-type-qualifier /// -void Parser::ParseObjCTypeName() { +Parser::TypeTy *Parser::ParseObjCTypeName() { assert(Tok.getKind() == tok::l_paren && "expected ("); SourceLocation LParenLoc = ConsumeParen(), RParenLoc; + TypeTy *Ty; while (isObjCTypeQualifier()) ConsumeToken(); if (isTypeSpecifierQualifier()) { - //TypeTy *Ty = ParseTypeName(); - //assert(Ty && "Parser::ParseObjCTypeName(): missing type"); - ParseTypeName(); // FIXME: when sema support is added. + Ty = ParseTypeName(); + // FIXME: back when Sema support is in place... + // assert(Ty && "Parser::ParseObjCTypeName(): missing type"); } if (Tok.getKind() != tok::r_paren) { MatchRHSPunctuation(tok::r_paren, LParenLoc); - return; + return 0; // FIXME: decide how we want to handle this error... } RParenLoc = ConsumeParen(); + return Ty; } /// objc-method-decl: @@ -473,40 +485,52 @@ void Parser::ParseObjCTypeName() { /// objc-keyword-attributes: [OBJC2] /// __attribute__((unused)) /// -void Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc) { +Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc) { + TypeTy *ReturnType = 0; + // Parse the return type. if (Tok.getKind() == tok::l_paren) - ParseObjCTypeName(); + ReturnType = ParseObjCTypeName(); IdentifierInfo *selIdent = ParseObjCSelector(); + + llvm::SmallVector KeyInfo; + int KeySlot = 0; if (Tok.getKind() == tok::colon) { - IdentifierInfo *keywordSelector = selIdent; + while (1) { + KeyInfo[KeySlot].SelectorName = selIdent; + // Each iteration parses a single keyword argument. if (Tok.getKind() != tok::colon) { Diag(Tok, diag::err_expected_colon); break; } - ConsumeToken(); // Eat the ':'. + KeyInfo[KeySlot].ColonLoc = ConsumeToken(); // Eat the ':'. if (Tok.getKind() == tok::l_paren) // Parse the argument type. - ParseObjCTypeName(); + KeyInfo[KeySlot].TypeInfo = ParseObjCTypeName(); // If attributes exist before the argument name, parse them. if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) - ParseAttributes(); + KeyInfo[KeySlot].AttrList = ParseAttributes(); if (Tok.getKind() != tok::identifier) { Diag(Tok, diag::err_expected_ident); // missing argument name. break; } + KeyInfo[KeySlot].ArgumentName = Tok.getIdentifierInfo(); ConsumeToken(); // Eat the identifier. + + // Rather than call out to the actions, try packaging up the info + // locally, like we do for Declarator. // FIXME: add Actions.BuildObjCKeyword() - keywordSelector = ParseObjCSelector(); - if (!keywordSelector && Tok.getKind() != tok::colon) + selIdent = ParseObjCSelector(); + if (!selIdent && Tok.getKind() != tok::colon) break; // We have a selector or a colon, continue parsing. + KeySlot++; } // Parse the (optional) parameter list. while (Tok.getKind() == tok::comma) { @@ -522,20 +546,34 @@ void Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc) { Declarator ParmDecl(DS, Declarator::PrototypeContext); ParseDeclarator(ParmDecl); } + AttributeList *methodAttrs = 0; + // If attributes exist after the method, parse them. + if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) + methodAttrs = ParseAttributes(); + + // FIXME: Add support for optional parmameter list... + return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, + &KeyInfo[0], KeyInfo.size(), + methodAttrs); } else if (!selIdent) { Diag(Tok, diag::err_expected_ident); // missing selector name. } - // FIXME: add Actions.BuildMethodSignature(). + AttributeList *methodAttrs = 0; + // If attributes exist after the method, parse them. + if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) + methodAttrs = ParseAttributes(); + return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, selIdent, + methodAttrs); } /// objc-protocol-refs: /// '<' identifier-list '>' /// -bool Parser::ParseObjCProtocolReferences() { +bool Parser::ParseObjCProtocolReferences( + llvm::SmallVectorImpl &ProtocolRefs) { assert(Tok.getKind() == tok::less && "expected <"); ConsumeToken(); // the "<" - llvm::SmallVector ProtocolRefs; while (1) { if (Tok.getKind() != tok::identifier) { @@ -574,11 +612,11 @@ bool Parser::ParseObjCProtocolReferences() { /// objc-instance-variable-decl: /// struct-declaration /// -void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl) { +void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl, + llvm::SmallVectorImpl &IvarDecls) { assert(Tok.getKind() == tok::l_brace && "expected {"); SourceLocation LBraceLoc = ConsumeBrace(); // the "{" - llvm::SmallVector IvarDecls; // While we still have something to read, read the instance variables. while (Tok.getKind() != tok::r_brace && @@ -685,10 +723,12 @@ Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) { } // Last, and definitely not least, parse a protocol declaration. if (Tok.getKind() == tok::less) { - if (ParseObjCProtocolReferences()) + llvm::SmallVector ProtocolRefs; + if (ParseObjCProtocolReferences(ProtocolRefs)) return 0; } - ParseObjCInterfaceDeclList(0/*FIXME*/); + llvm::SmallVector MethodDecls; + ParseObjCInterfaceDeclList(0/*FIXME*/, MethodDecls); // The @ sign was already consumed by ParseObjCInterfaceDeclList(). if (Tok.isObjCAtKeyword(tok::objc_end)) { @@ -754,8 +794,9 @@ Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration( } ConsumeToken(); // Consume super class name } + llvm::SmallVector IvarDecls; if (Tok.getKind() == tok::l_brace) - ParseObjCClassInstanceVariables(0/*FIXME*/); // we have ivars + ParseObjCClassInstanceVariables(0/*FIXME*/, IvarDecls); // we have ivars return 0; } diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index c793c5f0cf..ceddc1fe51 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -211,7 +211,7 @@ 3547129D0C88881300B3E1D5 /* PrettyPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrettyPrinter.h; path = clang/AST/PrettyPrinter.h; sourceTree = ""; }; 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = Parse/AttributeList.cpp; sourceTree = ""; }; 84D9A88B0C1A581300AC7ABC /* AttributeList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = AttributeList.h; path = clang/Parse/AttributeList.h; sourceTree = ""; }; - 8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "compiled.mach-o.executable"; path = clang; sourceTree = BUILT_PRODUCTS_DIR; }; + 8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = clang; sourceTree = BUILT_PRODUCTS_DIR; }; DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = ""; }; DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExprCXX.cpp; path = Parse/ParseExprCXX.cpp; sourceTree = ""; }; DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = ""; }; diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index ec9a4d0dd2..20845ad9d6 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -21,6 +21,7 @@ namespace clang { // Semantic. class DeclSpec; class Declarator; + class ObjcKeywordInfo; class AttributeList; // Parse. class Scope; @@ -430,7 +431,35 @@ public: tok::TokenKind Kind) { return 0; } + //===----------------------- Obj-C Declarations -------------------------===// + virtual DeclTy *ObjcStartClassInterface(SourceLocation AtInterafceLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *SuperName, SourceLocation SuperLoc, + IdentifierInfo **ProtocolNames, unsigned NumProtocols, + AttributeList *AttrList) { + return 0; + } + virtual void ObjCContinueClassInterface(SourceLocation InterfaceLoc) { + return; + } + virtual void ObjCStartCategoryInterface() { + return; + } + virtual void ObjCFinishInterface() { + return; + } + virtual DeclTy *ObjcBuildMethodDeclaration( + SourceLocation MethodLoc, tok::TokenKind MethodType, TypeTy *ReturnType, + ObjcKeywordInfo *Keywords, unsigned NumKeywords, AttributeList *attrs) { + return 0; + } + virtual DeclTy *ObjcBuildMethodDeclaration( + SourceLocation MethodLoc, tok::TokenKind MethodType, TypeTy *ReturnType, + IdentifierInfo *SelectorName, AttributeList *attrs) { + return 0; + } + //===----------------------- Obj-C Expressions --------------------------===// virtual ExprResult ParseObjCStringLiteral(ExprTy *string) { return 0; diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 6a15290072..de22360120 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -562,7 +562,24 @@ public: bool getInvalidType() { return InvalidType; } }; +struct ObjcKeywordInfo { + IdentifierInfo *SelectorName; // optional + SourceLocation SelectorLoc; + SourceLocation ColonLoc; + Action::TypeTy *TypeInfo; // optional + bool InvalidType; + IdentifierInfo *ArgumentName; + AttributeList *AttrList; + ObjcKeywordInfo() {} + ObjcKeywordInfo(IdentifierInfo *selName, SourceLocation sLoc, + SourceLocation cLoc, Action::TypeTy *tInfo, + IdentifierInfo *argName, AttributeList *aList) + : SelectorName(selName), SelectorLoc(sLoc), ColonLoc(cLoc), TypeInfo(tInfo), + ArgumentName(argName), AttrList(aList) { + } +}; + } // end namespace clang #endif diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index f05a2ec5b5..c49d242ab5 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -258,9 +258,11 @@ private: DeclTy *ParseObjCAtClassDeclaration(SourceLocation atLoc); DeclTy *ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, AttributeList *prefixAttrs = 0); - void ParseObjCClassInstanceVariables(DeclTy *interfaceDecl); - bool ParseObjCProtocolReferences(); - void ParseObjCInterfaceDeclList(DeclTy *interfaceDecl); + void ParseObjCClassInstanceVariables(DeclTy *interfaceDecl, + llvm::SmallVectorImpl &IvarDecls); + bool ParseObjCProtocolReferences(llvm::SmallVectorImpl &); + void ParseObjCInterfaceDeclList(DeclTy *interfaceDecl, + llvm::SmallVectorImpl &MethodDecls); DeclTy *ParseObjCAtProtocolDeclaration(SourceLocation atLoc); DeclTy *ParseObjCAtImplementationDeclaration(SourceLocation atLoc); DeclTy *ParseObjCAtEndDeclaration(SourceLocation atLoc); @@ -284,10 +286,10 @@ private: IdentifierInfo *ObjcPropertyAttrs[objc_NumAttrs]; bool isObjCPropertyAttribute(); - void ParseObjCTypeName(); + TypeTy *ParseObjCTypeName(); void ParseObjCMethodRequirement(); - void ParseObjCMethodPrototype(bool decl); - void ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc); + DeclTy *ParseObjCMethodPrototype(bool decl); + DeclTy *ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc); void ParseObjCPropertyAttribute(DeclTy *interfaceDecl); void ParseObjCPropertyDecl(DeclTy *interfaceDecl); -- 2.40.0