From: Fariborz Jahanian Date: Fri, 31 Aug 2007 16:11:31 +0000 (+0000) Subject: Author: F. Jahanian X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d0f97d1716a138a8d9e0df8e5af77334663723d8;p=clang Author: F. Jahanian Log: Implement parsing of objective-c's new @property declaration. Modified: include/clang/Basic/DiagnosticKinds.def include/clang/Parse/Parser.h Parse/ParseObjc.cpp Parse/Parser.cpp git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41644 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp index 7c0f84257e..83dba037fa 100644 --- a/Parse/ParseObjc.cpp +++ b/Parse/ParseObjc.cpp @@ -224,7 +224,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl) { ConsumeToken(); continue; } else if (ocKind == tok::objc_property) { - ParseObjCPropertyDecl(AtLoc); + ParseObjCPropertyDecl(0/*FIXME*/); continue; } else { Diag(Tok, diag::err_objc_illegal_interface_qual); @@ -246,8 +246,96 @@ void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl) { } } -void Parser::ParseObjCPropertyDecl(SourceLocation atLoc) { - assert(0 && "Unimp"); +/// Parse property attribute declarations. +/// +/// property-attr-decl: '(' property-attrlist ')' +/// property-attrlist: +/// property-attribute +/// property-attrlist ',' property-attribute +/// property-attribute: +/// getter '=' identifier +/// setter '=' identifier ':' +/// readonly +/// readwrite +/// assign +/// retain +/// copy +/// nonatomic +/// +void Parser::ParseObjCPropertyAttribute (DeclTy *interfaceDecl) { + SourceLocation loc = ConsumeParen(); // consume '(' + while (isObjCPropertyAttribute()) { + const IdentifierInfo *II = Tok.getIdentifierInfo(); + // getter/setter require extra treatment. + if (II == ObjcPropertyAttrs[objc_getter] || + II == ObjcPropertyAttrs[objc_setter]) { + // skip getter/setter part. + SourceLocation loc = ConsumeToken(); + if (Tok.getKind() == tok::equal) { + loc = ConsumeToken(); + if (Tok.getKind() == tok::identifier) { + if (II == ObjcPropertyAttrs[objc_setter]) { + loc = ConsumeToken(); // consume method name + if (Tok.getKind() != tok::colon) { + Diag(loc, diag::err_expected_colon); + SkipUntil(tok::r_paren,true,true); + break; + } + } + } + else { + Diag(loc, diag::err_expected_ident); + SkipUntil(tok::r_paren,true,true); + break; + } + } + else { + Diag(loc, diag::err_objc_expected_equal); + SkipUntil(tok::r_paren,true,true); + break; + } + } + ConsumeToken(); // consume last attribute token + if (Tok.getKind() == tok::comma) { + loc = ConsumeToken(); + continue; + } + if (Tok.getKind() == tok::r_paren) + break; + Diag(loc, diag::err_expected_rparen); + SkipUntil(tok::semi); + return; + } + if (Tok.getKind() == tok::r_paren) + ConsumeParen(); + else { + Diag(loc, diag::err_objc_expected_property_attr); + SkipUntil(tok::r_paren); // recover from error inside attribute list + } +} + +/// Main routine to parse property declaration. +/// +/// @property property-attr-decl[opt] property-component-decl ';' +/// +void Parser::ParseObjCPropertyDecl(DeclTy *interfaceDecl) { + assert(Tok.isObjCAtKeyword(tok::objc_property) && + "ParseObjCPropertyDecl(): Expected @property"); + ConsumeToken(); // the "property" identifier + // Parse property attribute list, if any. + if (Tok.getKind() == tok::l_paren) { + // property has attribute list. + ParseObjCPropertyAttribute(0/*FIXME*/); + } + // Parse declaration portion of @property. + llvm::SmallVector PropertyDecls; + ParseStructDeclaration(interfaceDecl, PropertyDecls); + if (Tok.getKind() == tok::semi) + ConsumeToken(); + else { + Diag(Tok, diag::err_expected_semi_decl_list); + SkipUntil(tok::r_brace, true, true); + } } /// objc-methodproto: @@ -312,6 +400,18 @@ bool Parser::isObjCTypeQualifier() { return false; } +/// property-attrlist: one of +/// readonly getter setter assign retain copy nonatomic +/// +bool Parser::isObjCPropertyAttribute() { + if (Tok.getKind() == tok::identifier) { + const IdentifierInfo *II = Tok.getIdentifierInfo(); + for (unsigned i = 0; i < objc_NumAttrs; ++i) + if (II == ObjcPropertyAttrs[i]) return true; + } + return false; +} + /// objc-type-name: /// '(' objc-type-qualifiers[opt] type-name ')' /// '(' objc-type-qualifiers[opt] ')' diff --git a/Parse/Parser.cpp b/Parse/Parser.cpp index 581d585a82..0a7ea58b04 100644 --- a/Parse/Parser.cpp +++ b/Parse/Parser.cpp @@ -258,6 +258,18 @@ void Parser::Initialize() { ObjcTypeQuals[objc_bycopy] = &PP.getIdentifierTable().get("bycopy"); ObjcTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref"); } + if (getLang().ObjC2) { + ObjcPropertyAttrs[objc_readonly] = &PP.getIdentifierTable().get("readonly"); + ObjcPropertyAttrs[objc_getter] = &PP.getIdentifierTable().get("getter"); + ObjcPropertyAttrs[objc_setter] = &PP.getIdentifierTable().get("setter"); + ObjcPropertyAttrs[objc_assign] = &PP.getIdentifierTable().get("assign"); + ObjcPropertyAttrs[objc_readwrite] = + &PP.getIdentifierTable().get("readwrite"); + ObjcPropertyAttrs[objc_retain] = &PP.getIdentifierTable().get("retain"); + ObjcPropertyAttrs[objc_copy] = &PP.getIdentifierTable().get("copy"); + ObjcPropertyAttrs[objc_nonatomic] = + &PP.getIdentifierTable().get("nonatomic"); + } } /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 9eaf4d4061..a5d276d33e 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -399,6 +399,10 @@ DIAG(err_objc_illegal_visibility_spec, ERROR, "illegal visibility specification") DIAG(err_objc_illegal_interface_qual, ERROR, "illegal interface qualifier") +DIAG(err_objc_expected_equal, ERROR, + "setter/getter expects '=' followed by name") +DIAG(err_objc_expected_property_attr, ERROR, + "unknown property attribute detected") //===----------------------------------------------------------------------===// // Semantic Analysis diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index ab6f84fb31..65d1ff6431 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -274,11 +274,20 @@ private: }; IdentifierInfo *ObjcTypeQuals[objc_NumQuals]; bool isObjCTypeQualifier(); + // Definitions for ObjC2's @property attributes. + enum ObjCPropertyAttr { + objc_readonly=0, objc_getter, objc_setter, objc_assign, + objc_readwrite, objc_retain, objc_copy, objc_nonatomic, objc_NumAttrs + }; + IdentifierInfo *ObjcPropertyAttrs[objc_NumAttrs]; + bool isObjCPropertyAttribute(); + void ParseObjCTypeName(); void ParseObjCMethodRequirement(); void ParseObjCMethodPrototype(); void ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc); - void ParseObjCPropertyDecl(SourceLocation atLoc); + void ParseObjCPropertyAttribute(DeclTy *interfaceDecl); + void ParseObjCPropertyDecl(DeclTy *interfaceDecl); void ParseObjCInstanceMethodDefinition(); void ParseObjCClassMethodDefinition();