ParseObjc.cpp revision 246e70f69cb8aeb67225c54690f1c6b25abd5a86
1//===--- ParseObjC.cpp - Objective C Parsing ------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the Objective-C portions of the Parser interface. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/Parse/Parser.h" 15#include "clang/Parse/DeclSpec.h" 16#include "clang/Parse/Scope.h" 17#include "clang/Basic/Diagnostic.h" 18#include "llvm/ADT/SmallVector.h" 19using namespace clang; 20 21 22/// ParseExternalDeclaration: 23/// external-declaration: [C99 6.9] 24/// [OBJC] objc-class-definition 25/// [OBJC] objc-class-declaration 26/// [OBJC] objc-alias-declaration 27/// [OBJC] objc-protocol-definition 28/// [OBJC] objc-method-definition 29/// [OBJC] '@' 'end' 30Parser::DeclTy *Parser::ParseObjCAtDirectives() { 31 SourceLocation AtLoc = ConsumeToken(); // the "@" 32 33 switch (Tok.getObjCKeywordID()) { 34 case tok::objc_class: 35 return ParseObjCAtClassDeclaration(AtLoc); 36 case tok::objc_interface: 37 return ParseObjCAtInterfaceDeclaration(AtLoc); 38 case tok::objc_protocol: 39 return ParseObjCAtProtocolDeclaration(AtLoc); 40 case tok::objc_implementation: 41 return ParseObjCAtImplementationDeclaration(AtLoc); 42 case tok::objc_end: 43 return ParseObjCAtEndDeclaration(AtLoc); 44 case tok::objc_compatibility_alias: 45 return ParseObjCAtAliasDeclaration(AtLoc); 46 case tok::objc_synthesize: 47 return ParseObjCPropertySynthesize(AtLoc); 48 case tok::objc_dynamic: 49 return ParseObjCPropertyDynamic(AtLoc); 50 default: 51 Diag(AtLoc, diag::err_unexpected_at); 52 SkipUntil(tok::semi); 53 return 0; 54 } 55} 56 57/// 58/// objc-class-declaration: 59/// '@' 'class' identifier-list ';' 60/// 61Parser::DeclTy *Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { 62 ConsumeToken(); // the identifier "class" 63 llvm::SmallVector<IdentifierInfo *, 8> ClassNames; 64 65 while (1) { 66 if (Tok.isNot(tok::identifier)) { 67 Diag(Tok, diag::err_expected_ident); 68 SkipUntil(tok::semi); 69 return 0; 70 } 71 ClassNames.push_back(Tok.getIdentifierInfo()); 72 ConsumeToken(); 73 74 if (Tok.isNot(tok::comma)) 75 break; 76 77 ConsumeToken(); 78 } 79 80 // Consume the ';'. 81 if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class")) 82 return 0; 83 84 return Actions.ActOnForwardClassDeclaration(atLoc, 85 &ClassNames[0], ClassNames.size()); 86} 87 88/// 89/// objc-interface: 90/// objc-class-interface-attributes[opt] objc-class-interface 91/// objc-category-interface 92/// 93/// objc-class-interface: 94/// '@' 'interface' identifier objc-superclass[opt] 95/// objc-protocol-refs[opt] 96/// objc-class-instance-variables[opt] 97/// objc-interface-decl-list 98/// @end 99/// 100/// objc-category-interface: 101/// '@' 'interface' identifier '(' identifier[opt] ')' 102/// objc-protocol-refs[opt] 103/// objc-interface-decl-list 104/// @end 105/// 106/// objc-superclass: 107/// ':' identifier 108/// 109/// objc-class-interface-attributes: 110/// __attribute__((visibility("default"))) 111/// __attribute__((visibility("hidden"))) 112/// __attribute__((deprecated)) 113/// __attribute__((unavailable)) 114/// __attribute__((objc_exception)) - used by NSException on 64-bit 115/// 116Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration( 117 SourceLocation atLoc, AttributeList *attrList) { 118 assert(Tok.isObjCAtKeyword(tok::objc_interface) && 119 "ParseObjCAtInterfaceDeclaration(): Expected @interface"); 120 ConsumeToken(); // the "interface" identifier 121 122 if (Tok.isNot(tok::identifier)) { 123 Diag(Tok, diag::err_expected_ident); // missing class or category name. 124 return 0; 125 } 126 // We have a class or category name - consume it. 127 IdentifierInfo *nameId = Tok.getIdentifierInfo(); 128 SourceLocation nameLoc = ConsumeToken(); 129 130 if (Tok.is(tok::l_paren)) { // we have a category. 131 SourceLocation lparenLoc = ConsumeParen(); 132 SourceLocation categoryLoc, rparenLoc; 133 IdentifierInfo *categoryId = 0; 134 135 // For ObjC2, the category name is optional (not an error). 136 if (Tok.is(tok::identifier)) { 137 categoryId = Tok.getIdentifierInfo(); 138 categoryLoc = ConsumeToken(); 139 } else if (!getLang().ObjC2) { 140 Diag(Tok, diag::err_expected_ident); // missing category name. 141 return 0; 142 } 143 if (Tok.isNot(tok::r_paren)) { 144 Diag(Tok, diag::err_expected_rparen); 145 SkipUntil(tok::r_paren, false); // don't stop at ';' 146 return 0; 147 } 148 rparenLoc = ConsumeParen(); 149 150 // Next, we need to check for any protocol references. 151 SourceLocation EndProtoLoc; 152 llvm::SmallVector<DeclTy *, 8> ProtocolRefs; 153 if (Tok.is(tok::less) && 154 ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc)) 155 return 0; 156 157 if (attrList) // categories don't support attributes. 158 Diag(Tok, diag::err_objc_no_attributes_on_category); 159 160 DeclTy *CategoryType = Actions.ActOnStartCategoryInterface(atLoc, 161 nameId, nameLoc, categoryId, categoryLoc, 162 &ProtocolRefs[0], ProtocolRefs.size(), 163 EndProtoLoc); 164 165 ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword); 166 167 // The @ sign was already consumed by ParseObjCInterfaceDeclList(). 168 if (Tok.isObjCAtKeyword(tok::objc_end)) { 169 ConsumeToken(); // the "end" identifier 170 return CategoryType; 171 } 172 Diag(Tok, diag::err_objc_missing_end); 173 return 0; 174 } 175 // Parse a class interface. 176 IdentifierInfo *superClassId = 0; 177 SourceLocation superClassLoc; 178 179 if (Tok.is(tok::colon)) { // a super class is specified. 180 ConsumeToken(); 181 if (Tok.isNot(tok::identifier)) { 182 Diag(Tok, diag::err_expected_ident); // missing super class name. 183 return 0; 184 } 185 superClassId = Tok.getIdentifierInfo(); 186 superClassLoc = ConsumeToken(); 187 } 188 // Next, we need to check for any protocol references. 189 llvm::SmallVector<Action::DeclTy*, 8> ProtocolRefs; 190 SourceLocation EndProtoLoc; 191 if (Tok.is(tok::less) && 192 ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc)) 193 return 0; 194 195 DeclTy *ClsType = 196 Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc, 197 superClassId, superClassLoc, 198 &ProtocolRefs[0], ProtocolRefs.size(), 199 EndProtoLoc, attrList); 200 201 if (Tok.is(tok::l_brace)) 202 ParseObjCClassInstanceVariables(ClsType, atLoc); 203 204 ParseObjCInterfaceDeclList(ClsType, tok::objc_interface); 205 206 // The @ sign was already consumed by ParseObjCInterfaceDeclList(). 207 if (Tok.isObjCAtKeyword(tok::objc_end)) { 208 ConsumeToken(); // the "end" identifier 209 return ClsType; 210 } 211 Diag(Tok, diag::err_objc_missing_end); 212 return 0; 213} 214 215/// constructSetterName - Return the setter name for the given 216/// identifier, i.e. "set" + Name where the initial character of Name 217/// has been capitalized. 218static IdentifierInfo *constructSetterName(IdentifierTable &Idents, 219 const IdentifierInfo *Name) { 220 unsigned N = Name->getLength(); 221 char *SelectorName = new char[3 + N]; 222 memcpy(SelectorName, "set", 3); 223 memcpy(&SelectorName[3], Name->getName(), N); 224 SelectorName[3] = toupper(SelectorName[3]); 225 226 IdentifierInfo *Setter = 227 &Idents.get(SelectorName, &SelectorName[3 + N]); 228 delete[] SelectorName; 229 return Setter; 230} 231 232/// objc-interface-decl-list: 233/// empty 234/// objc-interface-decl-list objc-property-decl [OBJC2] 235/// objc-interface-decl-list objc-method-requirement [OBJC2] 236/// objc-interface-decl-list objc-method-proto ';' 237/// objc-interface-decl-list declaration 238/// objc-interface-decl-list ';' 239/// 240/// objc-method-requirement: [OBJC2] 241/// @required 242/// @optional 243/// 244void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl, 245 tok::ObjCKeywordKind contextKey) { 246 llvm::SmallVector<DeclTy*, 32> allMethods; 247 llvm::SmallVector<DeclTy*, 16> allProperties; 248 tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword; 249 SourceLocation AtEndLoc; 250 251 while (1) { 252 if (Tok.is(tok::at)) { 253 SourceLocation AtLoc = ConsumeToken(); // the "@" 254 tok::ObjCKeywordKind ocKind = Tok.getObjCKeywordID(); 255 256 if (ocKind == tok::objc_end) { // terminate list 257 AtEndLoc = AtLoc; 258 break; 259 } else if (ocKind == tok::objc_required) { // protocols only 260 ConsumeToken(); 261 MethodImplKind = ocKind; 262 if (contextKey != tok::objc_protocol) 263 Diag(AtLoc, diag::err_objc_protocol_required); 264 } else if (ocKind == tok::objc_optional) { // protocols only 265 ConsumeToken(); 266 MethodImplKind = ocKind; 267 if (contextKey != tok::objc_protocol) 268 Diag(AtLoc, diag::err_objc_protocol_optional); 269 } else if (ocKind == tok::objc_property) { 270 ObjCDeclSpec OCDS; 271 ConsumeToken(); // the "property" identifier 272 // Parse property attribute list, if any. 273 if (Tok.is(tok::l_paren)) { 274 // property has attribute list. 275 ParseObjCPropertyAttribute(OCDS); 276 } 277 // Parse all the comma separated declarators. 278 DeclSpec DS; 279 llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators; 280 ParseStructDeclaration(DS, FieldDeclarators); 281 282 if (Tok.is(tok::semi)) 283 ConsumeToken(); 284 else { 285 Diag(Tok, diag::err_expected_semi_decl_list); 286 SkipUntil(tok::r_brace, true, true); 287 } 288 // Convert them all to property declarations. 289 for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) { 290 FieldDeclarator &FD = FieldDeclarators[i]; 291 // Install the property declarator into interfaceDecl. 292 Selector GetterSel = 293 PP.getSelectorTable().getNullarySelector(OCDS.getGetterName() 294 ? OCDS.getGetterName() 295 : FD.D.getIdentifier()); 296 IdentifierInfo *SetterName = OCDS.getSetterName(); 297 if (!SetterName) 298 SetterName = constructSetterName(PP.getIdentifierTable(), 299 FD.D.getIdentifier()); 300 Selector SetterSel = 301 PP.getSelectorTable().getUnarySelector(SetterName); 302 DeclTy *Property = Actions.ActOnProperty(CurScope, 303 AtLoc, FD, OCDS, 304 GetterSel, SetterSel, 305 MethodImplKind); 306 allProperties.push_back(Property); 307 } 308 continue; 309 } else { 310 Diag(Tok, diag::err_objc_illegal_interface_qual); 311 ConsumeToken(); 312 } 313 } 314 if (Tok.is(tok::minus) || Tok.is(tok::plus)) { 315 DeclTy *methodPrototype = 316 ParseObjCMethodPrototype(interfaceDecl, MethodImplKind); 317 allMethods.push_back(methodPrototype); 318 // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for 319 // method definitions. 320 ExpectAndConsume(tok::semi, diag::err_expected_semi_after,"method proto"); 321 continue; 322 } 323 else if (Tok.is(tok::at)) 324 continue; 325 326 if (Tok.is(tok::semi)) 327 ConsumeToken(); 328 else if (Tok.is(tok::eof)) 329 break; 330 else { 331 // FIXME: as the name implies, this rule allows function definitions. 332 // We could pass a flag or check for functions during semantic analysis. 333 ParseDeclarationOrFunctionDefinition(); 334 } 335 } 336 /// Insert collected methods declarations into the @interface object. 337 Actions.ActOnAtEnd(AtEndLoc, interfaceDecl, 338 allMethods.empty() ? 0 : &allMethods[0], 339 allMethods.size(), 340 allProperties.empty() ? 0 : &allProperties[0], 341 allProperties.size()); 342} 343 344/// Parse property attribute declarations. 345/// 346/// property-attr-decl: '(' property-attrlist ')' 347/// property-attrlist: 348/// property-attribute 349/// property-attrlist ',' property-attribute 350/// property-attribute: 351/// getter '=' identifier 352/// setter '=' identifier ':' 353/// readonly 354/// readwrite 355/// assign 356/// retain 357/// copy 358/// nonatomic 359/// 360void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { 361 SourceLocation loc = ConsumeParen(); // consume '(' 362 while (isObjCPropertyAttribute()) { 363 const IdentifierInfo *II = Tok.getIdentifierInfo(); 364 // getter/setter require extra treatment. 365 if (II == ObjCPropertyAttrs[objc_getter] || 366 II == ObjCPropertyAttrs[objc_setter]) { 367 // skip getter/setter part. 368 SourceLocation loc = ConsumeToken(); 369 if (Tok.is(tok::equal)) { 370 loc = ConsumeToken(); 371 if (Tok.is(tok::identifier)) { 372 if (II == ObjCPropertyAttrs[objc_setter]) { 373 DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter); 374 DS.setSetterName(Tok.getIdentifierInfo()); 375 loc = ConsumeToken(); // consume method name 376 if (Tok.isNot(tok::colon)) { 377 Diag(loc, diag::err_expected_colon); 378 SkipUntil(tok::r_paren,true,true); 379 break; 380 } 381 } 382 else { 383 DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter); 384 DS.setGetterName(Tok.getIdentifierInfo()); 385 } 386 } 387 else { 388 Diag(loc, diag::err_expected_ident); 389 SkipUntil(tok::r_paren,true,true); 390 break; 391 } 392 } 393 else { 394 Diag(loc, diag::err_objc_expected_equal); 395 SkipUntil(tok::r_paren,true,true); 396 break; 397 } 398 } 399 400 else if (II == ObjCPropertyAttrs[objc_readonly]) 401 DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readonly); 402 else if (II == ObjCPropertyAttrs[objc_assign]) 403 DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_assign); 404 else if (II == ObjCPropertyAttrs[objc_readwrite]) 405 DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readwrite); 406 else if (II == ObjCPropertyAttrs[objc_retain]) 407 DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_retain); 408 else if (II == ObjCPropertyAttrs[objc_copy]) 409 DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy); 410 else if (II == ObjCPropertyAttrs[objc_nonatomic]) 411 DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic); 412 413 ConsumeToken(); // consume last attribute token 414 if (Tok.is(tok::comma)) { 415 loc = ConsumeToken(); 416 continue; 417 } 418 if (Tok.is(tok::r_paren)) 419 break; 420 Diag(loc, diag::err_expected_rparen); 421 SkipUntil(tok::semi); 422 return; 423 } 424 if (Tok.is(tok::r_paren)) 425 ConsumeParen(); 426 else { 427 Diag(loc, diag::err_objc_expected_property_attr); 428 SkipUntil(tok::r_paren); // recover from error inside attribute list 429 } 430} 431 432/// objc-method-proto: 433/// objc-instance-method objc-method-decl objc-method-attributes[opt] 434/// objc-class-method objc-method-decl objc-method-attributes[opt] 435/// 436/// objc-instance-method: '-' 437/// objc-class-method: '+' 438/// 439/// objc-method-attributes: [OBJC2] 440/// __attribute__((deprecated)) 441/// 442Parser::DeclTy *Parser::ParseObjCMethodPrototype(DeclTy *IDecl, 443 tok::ObjCKeywordKind MethodImplKind) { 444 assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-"); 445 446 tok::TokenKind methodType = Tok.getKind(); 447 SourceLocation mLoc = ConsumeToken(); 448 449 DeclTy *MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl, MethodImplKind); 450 // Since this rule is used for both method declarations and definitions, 451 // the caller is (optionally) responsible for consuming the ';'. 452 return MDecl; 453} 454 455/// objc-selector: 456/// identifier 457/// one of 458/// enum struct union if else while do for switch case default 459/// break continue return goto asm sizeof typeof __alignof 460/// unsigned long const short volatile signed restrict _Complex 461/// in out inout bycopy byref oneway int char float double void _Bool 462/// 463IdentifierInfo *Parser::ParseObjCSelector(SourceLocation &SelectorLoc) { 464 switch (Tok.getKind()) { 465 default: 466 return 0; 467 case tok::identifier: 468 case tok::kw_asm: 469 case tok::kw_auto: 470 case tok::kw_bool: 471 case tok::kw_break: 472 case tok::kw_case: 473 case tok::kw_catch: 474 case tok::kw_char: 475 case tok::kw_class: 476 case tok::kw_const: 477 case tok::kw_const_cast: 478 case tok::kw_continue: 479 case tok::kw_default: 480 case tok::kw_delete: 481 case tok::kw_do: 482 case tok::kw_double: 483 case tok::kw_dynamic_cast: 484 case tok::kw_else: 485 case tok::kw_enum: 486 case tok::kw_explicit: 487 case tok::kw_export: 488 case tok::kw_extern: 489 case tok::kw_false: 490 case tok::kw_float: 491 case tok::kw_for: 492 case tok::kw_friend: 493 case tok::kw_goto: 494 case tok::kw_if: 495 case tok::kw_inline: 496 case tok::kw_int: 497 case tok::kw_long: 498 case tok::kw_mutable: 499 case tok::kw_namespace: 500 case tok::kw_new: 501 case tok::kw_operator: 502 case tok::kw_private: 503 case tok::kw_protected: 504 case tok::kw_public: 505 case tok::kw_register: 506 case tok::kw_reinterpret_cast: 507 case tok::kw_restrict: 508 case tok::kw_return: 509 case tok::kw_short: 510 case tok::kw_signed: 511 case tok::kw_sizeof: 512 case tok::kw_static: 513 case tok::kw_static_cast: 514 case tok::kw_struct: 515 case tok::kw_switch: 516 case tok::kw_template: 517 case tok::kw_this: 518 case tok::kw_throw: 519 case tok::kw_true: 520 case tok::kw_try: 521 case tok::kw_typedef: 522 case tok::kw_typeid: 523 case tok::kw_typename: 524 case tok::kw_typeof: 525 case tok::kw_union: 526 case tok::kw_unsigned: 527 case tok::kw_using: 528 case tok::kw_virtual: 529 case tok::kw_void: 530 case tok::kw_volatile: 531 case tok::kw_wchar_t: 532 case tok::kw_while: 533 case tok::kw__Bool: 534 case tok::kw__Complex: 535 case tok::kw___alignof: 536 IdentifierInfo *II = Tok.getIdentifierInfo(); 537 SelectorLoc = ConsumeToken(); 538 return II; 539 } 540} 541 542/// property-attrlist: one of 543/// readonly getter setter assign retain copy nonatomic 544/// 545bool Parser::isObjCPropertyAttribute() { 546 if (Tok.is(tok::identifier)) { 547 const IdentifierInfo *II = Tok.getIdentifierInfo(); 548 for (unsigned i = 0; i < objc_NumAttrs; ++i) 549 if (II == ObjCPropertyAttrs[i]) return true; 550 } 551 return false; 552} 553 554/// objc-for-collection-in: 'in' 555/// 556bool Parser::isTokIdentifier_in() const { 557 // FIXME: May have to do additional look-ahead to only allow for 558 // valid tokens following an 'in'; such as an identifier, unary operators, 559 // '[' etc. 560 return (getLang().ObjC2 && Tok.is(tok::identifier) && 561 Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]); 562} 563 564/// ParseObjCTypeQualifierList - This routine parses the objective-c's type 565/// qualifier list and builds their bitmask representation in the input 566/// argument. 567/// 568/// objc-type-qualifiers: 569/// objc-type-qualifier 570/// objc-type-qualifiers objc-type-qualifier 571/// 572void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) { 573 while (1) { 574 if (Tok.isNot(tok::identifier)) 575 return; 576 577 const IdentifierInfo *II = Tok.getIdentifierInfo(); 578 for (unsigned i = 0; i != objc_NumQuals; ++i) { 579 if (II != ObjCTypeQuals[i]) 580 continue; 581 582 ObjCDeclSpec::ObjCDeclQualifier Qual; 583 switch (i) { 584 default: assert(0 && "Unknown decl qualifier"); 585 case objc_in: Qual = ObjCDeclSpec::DQ_In; break; 586 case objc_out: Qual = ObjCDeclSpec::DQ_Out; break; 587 case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break; 588 case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break; 589 case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break; 590 case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break; 591 } 592 DS.setObjCDeclQualifier(Qual); 593 ConsumeToken(); 594 II = 0; 595 break; 596 } 597 598 // If this wasn't a recognized qualifier, bail out. 599 if (II) return; 600 } 601} 602 603/// objc-type-name: 604/// '(' objc-type-qualifiers[opt] type-name ')' 605/// '(' objc-type-qualifiers[opt] ')' 606/// 607Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) { 608 assert(Tok.is(tok::l_paren) && "expected ("); 609 610 SourceLocation LParenLoc = ConsumeParen(), RParenLoc; 611 SourceLocation TypeStartLoc = Tok.getLocation(); 612 TypeTy *Ty = 0; 613 614 // Parse type qualifiers, in, inout, etc. 615 ParseObjCTypeQualifierList(DS); 616 617 if (isTypeSpecifierQualifier()) { 618 Ty = ParseTypeName(); 619 // FIXME: back when Sema support is in place... 620 // assert(Ty && "Parser::ParseObjCTypeName(): missing type"); 621 } 622 623 if (Tok.isNot(tok::r_paren)) { 624 // If we didn't eat any tokens, then this isn't a type. 625 if (Tok.getLocation() == TypeStartLoc) { 626 Diag(Tok.getLocation(), diag::err_expected_type); 627 SkipUntil(tok::r_brace); 628 } else { 629 // Otherwise, we found *something*, but didn't get a ')' in the right 630 // place. Emit an error then return what we have as the type. 631 MatchRHSPunctuation(tok::r_paren, LParenLoc); 632 } 633 } 634 RParenLoc = ConsumeParen(); 635 return Ty; 636} 637 638/// objc-method-decl: 639/// objc-selector 640/// objc-keyword-selector objc-parmlist[opt] 641/// objc-type-name objc-selector 642/// objc-type-name objc-keyword-selector objc-parmlist[opt] 643/// 644/// objc-keyword-selector: 645/// objc-keyword-decl 646/// objc-keyword-selector objc-keyword-decl 647/// 648/// objc-keyword-decl: 649/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier 650/// objc-selector ':' objc-keyword-attributes[opt] identifier 651/// ':' objc-type-name objc-keyword-attributes[opt] identifier 652/// ':' objc-keyword-attributes[opt] identifier 653/// 654/// objc-parmlist: 655/// objc-parms objc-ellipsis[opt] 656/// 657/// objc-parms: 658/// objc-parms , parameter-declaration 659/// 660/// objc-ellipsis: 661/// , ... 662/// 663/// objc-keyword-attributes: [OBJC2] 664/// __attribute__((unused)) 665/// 666Parser::DeclTy *Parser::ParseObjCMethodDecl(SourceLocation mLoc, 667 tok::TokenKind mType, 668 DeclTy *IDecl, 669 tok::ObjCKeywordKind MethodImplKind) 670{ 671 // Parse the return type if present. 672 TypeTy *ReturnType = 0; 673 ObjCDeclSpec DSRet; 674 if (Tok.is(tok::l_paren)) 675 ReturnType = ParseObjCTypeName(DSRet); 676 677 SourceLocation selLoc; 678 IdentifierInfo *SelIdent = ParseObjCSelector(selLoc); 679 680 if (!SelIdent) { // missing selector name. 681 Diag(Tok.getLocation(), diag::err_expected_selector_for_method, 682 SourceRange(mLoc, Tok.getLocation())); 683 // Skip until we get a ; or {}. 684 SkipUntil(tok::r_brace); 685 return 0; 686 } 687 688 if (Tok.isNot(tok::colon)) { 689 // If attributes exist after the method, parse them. 690 AttributeList *MethodAttrs = 0; 691 if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) 692 MethodAttrs = ParseAttributes(); 693 694 Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); 695 return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), 696 mType, IDecl, DSRet, ReturnType, Sel, 697 0, 0, 0, MethodAttrs, MethodImplKind); 698 } 699 700 llvm::SmallVector<IdentifierInfo *, 12> KeyIdents; 701 llvm::SmallVector<Action::TypeTy *, 12> KeyTypes; 702 llvm::SmallVector<ObjCDeclSpec, 12> ArgTypeQuals; 703 llvm::SmallVector<IdentifierInfo *, 12> ArgNames; 704 705 Action::TypeTy *TypeInfo; 706 while (1) { 707 KeyIdents.push_back(SelIdent); 708 709 // Each iteration parses a single keyword argument. 710 if (Tok.isNot(tok::colon)) { 711 Diag(Tok, diag::err_expected_colon); 712 break; 713 } 714 ConsumeToken(); // Eat the ':'. 715 ObjCDeclSpec DSType; 716 if (Tok.is(tok::l_paren)) // Parse the argument type. 717 TypeInfo = ParseObjCTypeName(DSType); 718 else 719 TypeInfo = 0; 720 KeyTypes.push_back(TypeInfo); 721 ArgTypeQuals.push_back(DSType); 722 723 // If attributes exist before the argument name, parse them. 724 if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) 725 ParseAttributes(); // FIXME: pass attributes through. 726 727 if (Tok.isNot(tok::identifier)) { 728 Diag(Tok, diag::err_expected_ident); // missing argument name. 729 break; 730 } 731 ArgNames.push_back(Tok.getIdentifierInfo()); 732 ConsumeToken(); // Eat the identifier. 733 734 // Check for another keyword selector. 735 SourceLocation Loc; 736 SelIdent = ParseObjCSelector(Loc); 737 if (!SelIdent && Tok.isNot(tok::colon)) 738 break; 739 // We have a selector or a colon, continue parsing. 740 } 741 742 bool isVariadic = false; 743 744 // Parse the (optional) parameter list. 745 while (Tok.is(tok::comma)) { 746 ConsumeToken(); 747 if (Tok.is(tok::ellipsis)) { 748 isVariadic = true; 749 ConsumeToken(); 750 break; 751 } 752 // FIXME: implement this... 753 // Parse the c-style argument declaration-specifier. 754 DeclSpec DS; 755 ParseDeclarationSpecifiers(DS); 756 // Parse the declarator. 757 Declarator ParmDecl(DS, Declarator::PrototypeContext); 758 ParseDeclarator(ParmDecl); 759 } 760 761 // FIXME: Add support for optional parmameter list... 762 // If attributes exist after the method, parse them. 763 AttributeList *MethodAttrs = 0; 764 if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) 765 MethodAttrs = ParseAttributes(); 766 767 Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(), 768 &KeyIdents[0]); 769 return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), 770 mType, IDecl, DSRet, ReturnType, Sel, 771 &ArgTypeQuals[0], &KeyTypes[0], 772 &ArgNames[0], MethodAttrs, 773 MethodImplKind, isVariadic); 774} 775 776/// objc-protocol-refs: 777/// '<' identifier-list '>' 778/// 779bool Parser:: 780ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclTy*> &Protocols, 781 bool WarnOnDeclarations, SourceLocation &EndLoc) { 782 assert(Tok.is(tok::less) && "expected <"); 783 784 ConsumeToken(); // the "<" 785 786 llvm::SmallVector<IdentifierLocPair, 8> ProtocolIdents; 787 788 while (1) { 789 if (Tok.isNot(tok::identifier)) { 790 Diag(Tok, diag::err_expected_ident); 791 SkipUntil(tok::greater); 792 return true; 793 } 794 ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(), 795 Tok.getLocation())); 796 ConsumeToken(); 797 798 if (Tok.isNot(tok::comma)) 799 break; 800 ConsumeToken(); 801 } 802 803 // Consume the '>'. 804 if (Tok.isNot(tok::greater)) { 805 Diag(Tok, diag::err_expected_greater); 806 return true; 807 } 808 809 EndLoc = ConsumeAnyToken(); 810 811 // Convert the list of protocols identifiers into a list of protocol decls. 812 Actions.FindProtocolDeclaration(WarnOnDeclarations, 813 &ProtocolIdents[0], ProtocolIdents.size(), 814 Protocols); 815 return false; 816} 817 818/// objc-class-instance-variables: 819/// '{' objc-instance-variable-decl-list[opt] '}' 820/// 821/// objc-instance-variable-decl-list: 822/// objc-visibility-spec 823/// objc-instance-variable-decl ';' 824/// ';' 825/// objc-instance-variable-decl-list objc-visibility-spec 826/// objc-instance-variable-decl-list objc-instance-variable-decl ';' 827/// objc-instance-variable-decl-list ';' 828/// 829/// objc-visibility-spec: 830/// @private 831/// @protected 832/// @public 833/// @package [OBJC2] 834/// 835/// objc-instance-variable-decl: 836/// struct-declaration 837/// 838void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl, 839 SourceLocation atLoc) { 840 assert(Tok.is(tok::l_brace) && "expected {"); 841 llvm::SmallVector<DeclTy*, 32> AllIvarDecls; 842 llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators; 843 844 SourceLocation LBraceLoc = ConsumeBrace(); // the "{" 845 846 tok::ObjCKeywordKind visibility = tok::objc_protected; 847 // While we still have something to read, read the instance variables. 848 while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { 849 // Each iteration of this loop reads one objc-instance-variable-decl. 850 851 // Check for extraneous top-level semicolon. 852 if (Tok.is(tok::semi)) { 853 Diag(Tok, diag::ext_extra_struct_semi); 854 ConsumeToken(); 855 continue; 856 } 857 858 // Set the default visibility to private. 859 if (Tok.is(tok::at)) { // parse objc-visibility-spec 860 ConsumeToken(); // eat the @ sign 861 switch (Tok.getObjCKeywordID()) { 862 case tok::objc_private: 863 case tok::objc_public: 864 case tok::objc_protected: 865 case tok::objc_package: 866 visibility = Tok.getObjCKeywordID(); 867 ConsumeToken(); 868 continue; 869 default: 870 Diag(Tok, diag::err_objc_illegal_visibility_spec); 871 continue; 872 } 873 } 874 875 // Parse all the comma separated declarators. 876 DeclSpec DS; 877 FieldDeclarators.clear(); 878 ParseStructDeclaration(DS, FieldDeclarators); 879 880 // Convert them all to fields. 881 for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) { 882 FieldDeclarator &FD = FieldDeclarators[i]; 883 // Install the declarator into interfaceDecl. 884 DeclTy *Field = Actions.ActOnIvar(CurScope, 885 DS.getSourceRange().getBegin(), 886 FD.D, FD.BitfieldSize, visibility); 887 AllIvarDecls.push_back(Field); 888 } 889 890 if (Tok.is(tok::semi)) { 891 ConsumeToken(); 892 } else { 893 Diag(Tok, diag::err_expected_semi_decl_list); 894 // Skip to end of block or statement 895 SkipUntil(tok::r_brace, true, true); 896 } 897 } 898 SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); 899 // Call ActOnFields() even if we don't have any decls. This is useful 900 // for code rewriting tools that need to be aware of the empty list. 901 Actions.ActOnFields(CurScope, atLoc, interfaceDecl, 902 &AllIvarDecls[0], AllIvarDecls.size(), 903 LBraceLoc, RBraceLoc); 904 return; 905} 906 907/// objc-protocol-declaration: 908/// objc-protocol-definition 909/// objc-protocol-forward-reference 910/// 911/// objc-protocol-definition: 912/// @protocol identifier 913/// objc-protocol-refs[opt] 914/// objc-interface-decl-list 915/// @end 916/// 917/// objc-protocol-forward-reference: 918/// @protocol identifier-list ';' 919/// 920/// "@protocol identifier ;" should be resolved as "@protocol 921/// identifier-list ;": objc-interface-decl-list may not start with a 922/// semicolon in the first alternative if objc-protocol-refs are omitted. 923Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, 924 AttributeList *attrList) { 925 assert(Tok.isObjCAtKeyword(tok::objc_protocol) && 926 "ParseObjCAtProtocolDeclaration(): Expected @protocol"); 927 ConsumeToken(); // the "protocol" identifier 928 929 if (Tok.isNot(tok::identifier)) { 930 Diag(Tok, diag::err_expected_ident); // missing protocol name. 931 return 0; 932 } 933 // Save the protocol name, then consume it. 934 IdentifierInfo *protocolName = Tok.getIdentifierInfo(); 935 SourceLocation nameLoc = ConsumeToken(); 936 937 if (Tok.is(tok::semi)) { // forward declaration of one protocol. 938 IdentifierLocPair ProtoInfo(protocolName, nameLoc); 939 ConsumeToken(); 940 return Actions.ActOnForwardProtocolDeclaration(AtLoc, &ProtoInfo, 1); 941 } 942 943 if (Tok.is(tok::comma)) { // list of forward declarations. 944 llvm::SmallVector<IdentifierLocPair, 8> ProtocolRefs; 945 ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc)); 946 947 // Parse the list of forward declarations. 948 while (1) { 949 ConsumeToken(); // the ',' 950 if (Tok.isNot(tok::identifier)) { 951 Diag(Tok, diag::err_expected_ident); 952 SkipUntil(tok::semi); 953 return 0; 954 } 955 ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(), 956 Tok.getLocation())); 957 ConsumeToken(); // the identifier 958 959 if (Tok.isNot(tok::comma)) 960 break; 961 } 962 // Consume the ';'. 963 if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol")) 964 return 0; 965 966 return Actions.ActOnForwardProtocolDeclaration(AtLoc, 967 &ProtocolRefs[0], 968 ProtocolRefs.size()); 969 } 970 971 // Last, and definitely not least, parse a protocol declaration. 972 SourceLocation EndProtoLoc; 973 974 llvm::SmallVector<DeclTy *, 8> ProtocolRefs; 975 if (Tok.is(tok::less) && 976 ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc)) 977 return 0; 978 979 DeclTy *ProtoType = 980 Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc, 981 &ProtocolRefs[0], ProtocolRefs.size(), 982 EndProtoLoc, attrList); 983 ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol); 984 985 // The @ sign was already consumed by ParseObjCInterfaceDeclList(). 986 if (Tok.isObjCAtKeyword(tok::objc_end)) { 987 ConsumeToken(); // the "end" identifier 988 return ProtoType; 989 } 990 Diag(Tok, diag::err_objc_missing_end); 991 return 0; 992} 993 994/// objc-implementation: 995/// objc-class-implementation-prologue 996/// objc-category-implementation-prologue 997/// 998/// objc-class-implementation-prologue: 999/// @implementation identifier objc-superclass[opt] 1000/// objc-class-instance-variables[opt] 1001/// 1002/// objc-category-implementation-prologue: 1003/// @implementation identifier ( identifier ) 1004 1005Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration( 1006 SourceLocation atLoc) { 1007 assert(Tok.isObjCAtKeyword(tok::objc_implementation) && 1008 "ParseObjCAtImplementationDeclaration(): Expected @implementation"); 1009 ConsumeToken(); // the "implementation" identifier 1010 1011 if (Tok.isNot(tok::identifier)) { 1012 Diag(Tok, diag::err_expected_ident); // missing class or category name. 1013 return 0; 1014 } 1015 // We have a class or category name - consume it. 1016 IdentifierInfo *nameId = Tok.getIdentifierInfo(); 1017 SourceLocation nameLoc = ConsumeToken(); // consume class or category name 1018 1019 if (Tok.is(tok::l_paren)) { 1020 // we have a category implementation. 1021 SourceLocation lparenLoc = ConsumeParen(); 1022 SourceLocation categoryLoc, rparenLoc; 1023 IdentifierInfo *categoryId = 0; 1024 1025 if (Tok.is(tok::identifier)) { 1026 categoryId = Tok.getIdentifierInfo(); 1027 categoryLoc = ConsumeToken(); 1028 } else { 1029 Diag(Tok, diag::err_expected_ident); // missing category name. 1030 return 0; 1031 } 1032 if (Tok.isNot(tok::r_paren)) { 1033 Diag(Tok, diag::err_expected_rparen); 1034 SkipUntil(tok::r_paren, false); // don't stop at ';' 1035 return 0; 1036 } 1037 rparenLoc = ConsumeParen(); 1038 DeclTy *ImplCatType = Actions.ActOnStartCategoryImplementation( 1039 atLoc, nameId, nameLoc, categoryId, 1040 categoryLoc); 1041 ObjCImpDecl = ImplCatType; 1042 return 0; 1043 } 1044 // We have a class implementation 1045 SourceLocation superClassLoc; 1046 IdentifierInfo *superClassId = 0; 1047 if (Tok.is(tok::colon)) { 1048 // We have a super class 1049 ConsumeToken(); 1050 if (Tok.isNot(tok::identifier)) { 1051 Diag(Tok, diag::err_expected_ident); // missing super class name. 1052 return 0; 1053 } 1054 superClassId = Tok.getIdentifierInfo(); 1055 superClassLoc = ConsumeToken(); // Consume super class name 1056 } 1057 DeclTy *ImplClsType = Actions.ActOnStartClassImplementation( 1058 atLoc, nameId, nameLoc, 1059 superClassId, superClassLoc); 1060 1061 if (Tok.is(tok::l_brace)) // we have ivars 1062 ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/, atLoc); 1063 ObjCImpDecl = ImplClsType; 1064 1065 return 0; 1066} 1067 1068Parser::DeclTy *Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) { 1069 assert(Tok.isObjCAtKeyword(tok::objc_end) && 1070 "ParseObjCAtEndDeclaration(): Expected @end"); 1071 ConsumeToken(); // the "end" identifier 1072 if (ObjCImpDecl) 1073 Actions.ActOnAtEnd(atLoc, ObjCImpDecl); 1074 else 1075 Diag(atLoc, diag::warn_expected_implementation); // missing @implementation 1076 return ObjCImpDecl; 1077} 1078 1079/// compatibility-alias-decl: 1080/// @compatibility_alias alias-name class-name ';' 1081/// 1082Parser::DeclTy *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) { 1083 assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) && 1084 "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias"); 1085 ConsumeToken(); // consume compatibility_alias 1086 if (Tok.isNot(tok::identifier)) { 1087 Diag(Tok, diag::err_expected_ident); 1088 return 0; 1089 } 1090 IdentifierInfo *aliasId = Tok.getIdentifierInfo(); 1091 SourceLocation aliasLoc = ConsumeToken(); // consume alias-name 1092 if (Tok.isNot(tok::identifier)) { 1093 Diag(Tok, diag::err_expected_ident); 1094 return 0; 1095 } 1096 IdentifierInfo *classId = Tok.getIdentifierInfo(); 1097 SourceLocation classLoc = ConsumeToken(); // consume class-name; 1098 if (Tok.isNot(tok::semi)) { 1099 Diag(Tok, diag::err_expected_semi_after, "@compatibility_alias"); 1100 return 0; 1101 } 1102 DeclTy *ClsType = Actions.ActOnCompatiblityAlias(atLoc, 1103 aliasId, aliasLoc, 1104 classId, classLoc); 1105 return ClsType; 1106} 1107 1108/// property-synthesis: 1109/// @synthesize property-ivar-list ';' 1110/// 1111/// property-ivar-list: 1112/// property-ivar 1113/// property-ivar-list ',' property-ivar 1114/// 1115/// property-ivar: 1116/// identifier 1117/// identifier '=' identifier 1118/// 1119Parser::DeclTy *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { 1120 assert(Tok.isObjCAtKeyword(tok::objc_synthesize) && 1121 "ParseObjCPropertyDynamic(): Expected '@synthesize'"); 1122 SourceLocation loc = ConsumeToken(); // consume synthesize 1123 if (Tok.isNot(tok::identifier)) { 1124 Diag(Tok, diag::err_expected_ident); 1125 return 0; 1126 } 1127 while (Tok.is(tok::identifier)) { 1128 IdentifierInfo *propertyIvar = 0; 1129 IdentifierInfo *propertyId = Tok.getIdentifierInfo(); 1130 SourceLocation propertyLoc = ConsumeToken(); // consume property name 1131 if (Tok.is(tok::equal)) { 1132 // property '=' ivar-name 1133 ConsumeToken(); // consume '=' 1134 if (Tok.isNot(tok::identifier)) { 1135 Diag(Tok, diag::err_expected_ident); 1136 break; 1137 } 1138 propertyIvar = Tok.getIdentifierInfo(); 1139 ConsumeToken(); // consume ivar-name 1140 } 1141 Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, true, ObjCImpDecl, 1142 propertyId, propertyIvar); 1143 if (Tok.isNot(tok::comma)) 1144 break; 1145 ConsumeToken(); // consume ',' 1146 } 1147 if (Tok.isNot(tok::semi)) 1148 Diag(Tok, diag::err_expected_semi_after, "@synthesize"); 1149 return 0; 1150} 1151 1152/// property-dynamic: 1153/// @dynamic property-list 1154/// 1155/// property-list: 1156/// identifier 1157/// property-list ',' identifier 1158/// 1159Parser::DeclTy *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { 1160 assert(Tok.isObjCAtKeyword(tok::objc_dynamic) && 1161 "ParseObjCPropertyDynamic(): Expected '@dynamic'"); 1162 SourceLocation loc = ConsumeToken(); // consume dynamic 1163 if (Tok.isNot(tok::identifier)) { 1164 Diag(Tok, diag::err_expected_ident); 1165 return 0; 1166 } 1167 while (Tok.is(tok::identifier)) { 1168 IdentifierInfo *propertyId = Tok.getIdentifierInfo(); 1169 SourceLocation propertyLoc = ConsumeToken(); // consume property name 1170 Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, false, ObjCImpDecl, 1171 propertyId, 0); 1172 1173 if (Tok.isNot(tok::comma)) 1174 break; 1175 ConsumeToken(); // consume ',' 1176 } 1177 if (Tok.isNot(tok::semi)) 1178 Diag(Tok, diag::err_expected_semi_after, "@dynamic"); 1179 return 0; 1180} 1181 1182/// objc-throw-statement: 1183/// throw expression[opt]; 1184/// 1185Parser::StmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) { 1186 ExprResult Res; 1187 ConsumeToken(); // consume throw 1188 if (Tok.isNot(tok::semi)) { 1189 Res = ParseExpression(); 1190 if (Res.isInvalid) { 1191 SkipUntil(tok::semi); 1192 return true; 1193 } 1194 } 1195 ConsumeToken(); // consume ';' 1196 return Actions.ActOnObjCAtThrowStmt(atLoc, Res.Val); 1197} 1198 1199/// objc-synchronized-statement: 1200/// @synchronized '(' expression ')' compound-statement 1201/// 1202Parser::StmtResult Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) { 1203 ConsumeToken(); // consume synchronized 1204 if (Tok.isNot(tok::l_paren)) { 1205 Diag (Tok, diag::err_expected_lparen_after, "@synchronized"); 1206 return true; 1207 } 1208 ConsumeParen(); // '(' 1209 ExprResult Res = ParseExpression(); 1210 if (Res.isInvalid) { 1211 SkipUntil(tok::semi); 1212 return true; 1213 } 1214 if (Tok.isNot(tok::r_paren)) { 1215 Diag (Tok, diag::err_expected_lbrace); 1216 return true; 1217 } 1218 ConsumeParen(); // ')' 1219 if (Tok.isNot(tok::l_brace)) { 1220 Diag (Tok, diag::err_expected_lbrace); 1221 return true; 1222 } 1223 // Enter a scope to hold everything within the compound stmt. Compound 1224 // statements can always hold declarations. 1225 EnterScope(Scope::DeclScope); 1226 1227 StmtResult SynchBody = ParseCompoundStatementBody(); 1228 1229 ExitScope(); 1230 if (SynchBody.isInvalid) 1231 SynchBody = Actions.ActOnNullStmt(Tok.getLocation()); 1232 return Actions.ActOnObjCAtSynchronizedStmt(atLoc, Res.Val, SynchBody.Val); 1233} 1234 1235/// objc-try-catch-statement: 1236/// @try compound-statement objc-catch-list[opt] 1237/// @try compound-statement objc-catch-list[opt] @finally compound-statement 1238/// 1239/// objc-catch-list: 1240/// @catch ( parameter-declaration ) compound-statement 1241/// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement 1242/// catch-parameter-declaration: 1243/// parameter-declaration 1244/// '...' [OBJC2] 1245/// 1246Parser::StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { 1247 bool catch_or_finally_seen = false; 1248 1249 ConsumeToken(); // consume try 1250 if (Tok.isNot(tok::l_brace)) { 1251 Diag (Tok, diag::err_expected_lbrace); 1252 return true; 1253 } 1254 StmtResult CatchStmts; 1255 StmtResult FinallyStmt; 1256 StmtResult TryBody = ParseCompoundStatementBody(); 1257 if (TryBody.isInvalid) 1258 TryBody = Actions.ActOnNullStmt(Tok.getLocation()); 1259 1260 while (Tok.is(tok::at)) { 1261 // At this point, we need to lookahead to determine if this @ is the start 1262 // of an @catch or @finally. We don't want to consume the @ token if this 1263 // is an @try or @encode or something else. 1264 Token AfterAt = GetLookAheadToken(1); 1265 if (!AfterAt.isObjCAtKeyword(tok::objc_catch) && 1266 !AfterAt.isObjCAtKeyword(tok::objc_finally)) 1267 break; 1268 1269 SourceLocation AtCatchFinallyLoc = ConsumeToken(); 1270 if (Tok.isObjCAtKeyword(tok::objc_catch)) { 1271 StmtTy *FirstPart = 0; 1272 ConsumeToken(); // consume catch 1273 if (Tok.is(tok::l_paren)) { 1274 ConsumeParen(); 1275 EnterScope(Scope::DeclScope); 1276 if (Tok.isNot(tok::ellipsis)) { 1277 DeclSpec DS; 1278 ParseDeclarationSpecifiers(DS); 1279 // For some odd reason, the name of the exception variable is 1280 // optional. As a result, we need to use PrototypeContext. 1281 Declarator DeclaratorInfo(DS, Declarator::PrototypeContext); 1282 ParseDeclarator(DeclaratorInfo); 1283 if (DeclaratorInfo.getIdentifier()) { 1284 DeclTy *aBlockVarDecl = Actions.ActOnDeclarator(CurScope, 1285 DeclaratorInfo, 0); 1286 StmtResult stmtResult = 1287 Actions.ActOnDeclStmt(aBlockVarDecl, 1288 DS.getSourceRange().getBegin(), 1289 DeclaratorInfo.getSourceRange().getEnd()); 1290 FirstPart = stmtResult.isInvalid ? 0 : stmtResult.Val; 1291 } 1292 } else 1293 ConsumeToken(); // consume '...' 1294 SourceLocation RParenLoc = ConsumeParen(); 1295 1296 StmtResult CatchBody(true); 1297 if (Tok.is(tok::l_brace)) 1298 CatchBody = ParseCompoundStatementBody(); 1299 else 1300 Diag(Tok, diag::err_expected_lbrace); 1301 if (CatchBody.isInvalid) 1302 CatchBody = Actions.ActOnNullStmt(Tok.getLocation()); 1303 CatchStmts = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc, RParenLoc, 1304 FirstPart, CatchBody.Val, CatchStmts.Val); 1305 ExitScope(); 1306 } else { 1307 Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after, 1308 "@catch clause"); 1309 return true; 1310 } 1311 catch_or_finally_seen = true; 1312 } else { 1313 assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?"); 1314 ConsumeToken(); // consume finally 1315 EnterScope(Scope::DeclScope); 1316 1317 1318 StmtResult FinallyBody(true); 1319 if (Tok.is(tok::l_brace)) 1320 FinallyBody = ParseCompoundStatementBody(); 1321 else 1322 Diag(Tok, diag::err_expected_lbrace); 1323 if (FinallyBody.isInvalid) 1324 FinallyBody = Actions.ActOnNullStmt(Tok.getLocation()); 1325 FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc, 1326 FinallyBody.Val); 1327 catch_or_finally_seen = true; 1328 ExitScope(); 1329 break; 1330 } 1331 } 1332 if (!catch_or_finally_seen) { 1333 Diag(atLoc, diag::err_missing_catch_finally); 1334 return true; 1335 } 1336 return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.Val, CatchStmts.Val, 1337 FinallyStmt.Val); 1338} 1339 1340/// objc-method-def: objc-method-proto ';'[opt] '{' body '}' 1341/// 1342Parser::DeclTy *Parser::ParseObjCMethodDefinition() { 1343 DeclTy *MDecl = ParseObjCMethodPrototype(ObjCImpDecl); 1344 // parse optional ';' 1345 if (Tok.is(tok::semi)) 1346 ConsumeToken(); 1347 1348 // We should have an opening brace now. 1349 if (Tok.isNot(tok::l_brace)) { 1350 Diag(Tok, diag::err_expected_method_body); 1351 1352 // Skip over garbage, until we get to '{'. Don't eat the '{'. 1353 SkipUntil(tok::l_brace, true, true); 1354 1355 // If we didn't find the '{', bail out. 1356 if (Tok.isNot(tok::l_brace)) 1357 return 0; 1358 } 1359 SourceLocation BraceLoc = Tok.getLocation(); 1360 1361 // Enter a scope for the method body. 1362 EnterScope(Scope::FnScope|Scope::DeclScope); 1363 1364 // Tell the actions module that we have entered a method definition with the 1365 // specified Declarator for the method. 1366 Actions.ObjCActOnStartOfMethodDef(CurScope, MDecl); 1367 1368 StmtResult FnBody = ParseCompoundStatementBody(); 1369 1370 // If the function body could not be parsed, make a bogus compoundstmt. 1371 if (FnBody.isInvalid) 1372 FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc, 0, 0, false); 1373 1374 // Leave the function body scope. 1375 ExitScope(); 1376 1377 // TODO: Pass argument information. 1378 Actions.ActOnFinishFunctionBody(MDecl, FnBody.Val); 1379 return MDecl; 1380} 1381 1382Parser::StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { 1383 if (Tok.isObjCAtKeyword(tok::objc_try)) { 1384 return ParseObjCTryStmt(AtLoc); 1385 } else if (Tok.isObjCAtKeyword(tok::objc_throw)) 1386 return ParseObjCThrowStmt(AtLoc); 1387 else if (Tok.isObjCAtKeyword(tok::objc_synchronized)) 1388 return ParseObjCSynchronizedStmt(AtLoc); 1389 ExprResult Res = ParseExpressionWithLeadingAt(AtLoc); 1390 if (Res.isInvalid) { 1391 // If the expression is invalid, skip ahead to the next semicolon. Not 1392 // doing this opens us up to the possibility of infinite loops if 1393 // ParseExpression does not consume any tokens. 1394 SkipUntil(tok::semi); 1395 return true; 1396 } 1397 // Otherwise, eat the semicolon. 1398 ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); 1399 return Actions.ActOnExprStmt(Res.Val); 1400} 1401 1402Parser::ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { 1403 switch (Tok.getKind()) { 1404 case tok::string_literal: // primary-expression: string-literal 1405 case tok::wide_string_literal: 1406 return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc)); 1407 default: 1408 if (Tok.getIdentifierInfo() == 0) 1409 return Diag(AtLoc, diag::err_unexpected_at); 1410 1411 switch (Tok.getIdentifierInfo()->getObjCKeywordID()) { 1412 case tok::objc_encode: 1413 return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc)); 1414 case tok::objc_protocol: 1415 return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc)); 1416 case tok::objc_selector: 1417 return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc)); 1418 default: 1419 return Diag(AtLoc, diag::err_unexpected_at); 1420 } 1421 } 1422} 1423 1424/// objc-message-expr: 1425/// '[' objc-receiver objc-message-args ']' 1426/// 1427/// objc-receiver: 1428/// expression 1429/// class-name 1430/// type-name 1431Parser::ExprResult Parser::ParseObjCMessageExpression() { 1432 assert(Tok.is(tok::l_square) && "'[' expected"); 1433 SourceLocation LBracLoc = ConsumeBracket(); // consume '[' 1434 1435 // Parse receiver 1436 if (isTokObjCMessageIdentifierReceiver()) { 1437 IdentifierInfo *ReceiverName = Tok.getIdentifierInfo(); 1438 ConsumeToken(); 1439 return ParseObjCMessageExpressionBody(LBracLoc, ReceiverName, 0); 1440 } 1441 1442 ExprResult Res = ParseExpression(); 1443 if (Res.isInvalid) { 1444 SkipUntil(tok::r_square); 1445 return Res; 1446 } 1447 1448 return ParseObjCMessageExpressionBody(LBracLoc, 0, Res.Val); 1449} 1450 1451/// ParseObjCMessageExpressionBody - Having parsed "'[' objc-receiver", parse 1452/// the rest of a message expression. 1453/// 1454/// objc-message-args: 1455/// objc-selector 1456/// objc-keywordarg-list 1457/// 1458/// objc-keywordarg-list: 1459/// objc-keywordarg 1460/// objc-keywordarg-list objc-keywordarg 1461/// 1462/// objc-keywordarg: 1463/// selector-name[opt] ':' objc-keywordexpr 1464/// 1465/// objc-keywordexpr: 1466/// nonempty-expr-list 1467/// 1468/// nonempty-expr-list: 1469/// assignment-expression 1470/// nonempty-expr-list , assignment-expression 1471/// 1472Parser::ExprResult 1473Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, 1474 IdentifierInfo *ReceiverName, 1475 ExprTy *ReceiverExpr) { 1476 // Parse objc-selector 1477 SourceLocation Loc; 1478 IdentifierInfo *selIdent = ParseObjCSelector(Loc); 1479 1480 llvm::SmallVector<IdentifierInfo *, 12> KeyIdents; 1481 llvm::SmallVector<Action::ExprTy *, 12> KeyExprs; 1482 1483 if (Tok.is(tok::colon)) { 1484 while (1) { 1485 // Each iteration parses a single keyword argument. 1486 KeyIdents.push_back(selIdent); 1487 1488 if (Tok.isNot(tok::colon)) { 1489 Diag(Tok, diag::err_expected_colon); 1490 // We must manually skip to a ']', otherwise the expression skipper will 1491 // stop at the ']' when it skips to the ';'. We want it to skip beyond 1492 // the enclosing expression. 1493 SkipUntil(tok::r_square); 1494 return true; 1495 } 1496 1497 ConsumeToken(); // Eat the ':'. 1498 /// Parse the expression after ':' 1499 ExprResult Res = ParseAssignmentExpression(); 1500 if (Res.isInvalid) { 1501 // We must manually skip to a ']', otherwise the expression skipper will 1502 // stop at the ']' when it skips to the ';'. We want it to skip beyond 1503 // the enclosing expression. 1504 SkipUntil(tok::r_square); 1505 return Res; 1506 } 1507 1508 // We have a valid expression. 1509 KeyExprs.push_back(Res.Val); 1510 1511 // Check for another keyword selector. 1512 selIdent = ParseObjCSelector(Loc); 1513 if (!selIdent && Tok.isNot(tok::colon)) 1514 break; 1515 // We have a selector or a colon, continue parsing. 1516 } 1517 // Parse the, optional, argument list, comma separated. 1518 while (Tok.is(tok::comma)) { 1519 ConsumeToken(); // Eat the ','. 1520 /// Parse the expression after ',' 1521 ExprResult Res = ParseAssignmentExpression(); 1522 if (Res.isInvalid) { 1523 // We must manually skip to a ']', otherwise the expression skipper will 1524 // stop at the ']' when it skips to the ';'. We want it to skip beyond 1525 // the enclosing expression. 1526 SkipUntil(tok::r_square); 1527 return Res; 1528 } 1529 1530 // We have a valid expression. 1531 KeyExprs.push_back(Res.Val); 1532 } 1533 } else if (!selIdent) { 1534 Diag(Tok, diag::err_expected_ident); // missing selector name. 1535 1536 // We must manually skip to a ']', otherwise the expression skipper will 1537 // stop at the ']' when it skips to the ';'. We want it to skip beyond 1538 // the enclosing expression. 1539 SkipUntil(tok::r_square); 1540 return true; 1541 } 1542 1543 if (Tok.isNot(tok::r_square)) { 1544 Diag(Tok, diag::err_expected_rsquare); 1545 // We must manually skip to a ']', otherwise the expression skipper will 1546 // stop at the ']' when it skips to the ';'. We want it to skip beyond 1547 // the enclosing expression. 1548 SkipUntil(tok::r_square); 1549 return true; 1550 } 1551 1552 SourceLocation RBracLoc = ConsumeBracket(); // consume ']' 1553 1554 unsigned nKeys = KeyIdents.size(); 1555 if (nKeys == 0) 1556 KeyIdents.push_back(selIdent); 1557 Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]); 1558 1559 // We've just parsed a keyword message. 1560 if (ReceiverName) 1561 return Actions.ActOnClassMessage(CurScope, 1562 ReceiverName, Sel, LBracLoc, RBracLoc, 1563 &KeyExprs[0], KeyExprs.size()); 1564 return Actions.ActOnInstanceMessage(ReceiverExpr, Sel, LBracLoc, RBracLoc, 1565 &KeyExprs[0], KeyExprs.size()); 1566} 1567 1568Parser::ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) { 1569 ExprResult Res = ParseStringLiteralExpression(); 1570 if (Res.isInvalid) return Res; 1571 1572 // @"foo" @"bar" is a valid concatenated string. Eat any subsequent string 1573 // expressions. At this point, we know that the only valid thing that starts 1574 // with '@' is an @"". 1575 llvm::SmallVector<SourceLocation, 4> AtLocs; 1576 llvm::SmallVector<ExprTy*, 4> AtStrings; 1577 AtLocs.push_back(AtLoc); 1578 AtStrings.push_back(Res.Val); 1579 1580 while (Tok.is(tok::at)) { 1581 AtLocs.push_back(ConsumeToken()); // eat the @. 1582 1583 ExprResult Res(true); // Invalid unless there is a string literal. 1584 if (isTokenStringLiteral()) 1585 Res = ParseStringLiteralExpression(); 1586 else 1587 Diag(Tok, diag::err_objc_concat_string); 1588 1589 if (Res.isInvalid) { 1590 while (!AtStrings.empty()) { 1591 Actions.DeleteExpr(AtStrings.back()); 1592 AtStrings.pop_back(); 1593 } 1594 return Res; 1595 } 1596 1597 AtStrings.push_back(Res.Val); 1598 } 1599 1600 return Actions.ParseObjCStringLiteral(&AtLocs[0], &AtStrings[0], 1601 AtStrings.size()); 1602} 1603 1604/// objc-encode-expression: 1605/// @encode ( type-name ) 1606Parser::ExprResult Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) { 1607 assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!"); 1608 1609 SourceLocation EncLoc = ConsumeToken(); 1610 1611 if (Tok.isNot(tok::l_paren)) 1612 return Diag(Tok, diag::err_expected_lparen_after, "@encode"); 1613 1614 SourceLocation LParenLoc = ConsumeParen(); 1615 1616 TypeTy *Ty = ParseTypeName(); 1617 1618 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); 1619 1620 return Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, LParenLoc, Ty, 1621 RParenLoc); 1622} 1623 1624/// objc-protocol-expression 1625/// @protocol ( protocol-name ) 1626 1627Parser::ExprResult Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) 1628{ 1629 SourceLocation ProtoLoc = ConsumeToken(); 1630 1631 if (Tok.isNot(tok::l_paren)) 1632 return Diag(Tok, diag::err_expected_lparen_after, "@protocol"); 1633 1634 SourceLocation LParenLoc = ConsumeParen(); 1635 1636 if (Tok.isNot(tok::identifier)) 1637 return Diag(Tok, diag::err_expected_ident); 1638 1639 IdentifierInfo *protocolId = Tok.getIdentifierInfo(); 1640 ConsumeToken(); 1641 1642 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); 1643 1644 return Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc, 1645 LParenLoc, RParenLoc); 1646} 1647 1648/// objc-selector-expression 1649/// @selector '(' objc-keyword-selector ')' 1650Parser::ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) 1651{ 1652 SourceLocation SelectorLoc = ConsumeToken(); 1653 1654 if (Tok.isNot(tok::l_paren)) 1655 return Diag(Tok, diag::err_expected_lparen_after, "@selector"); 1656 1657 llvm::SmallVector<IdentifierInfo *, 12> KeyIdents; 1658 SourceLocation LParenLoc = ConsumeParen(); 1659 SourceLocation sLoc; 1660 IdentifierInfo *SelIdent = ParseObjCSelector(sLoc); 1661 if (!SelIdent && Tok.isNot(tok::colon)) 1662 return Diag(Tok, diag::err_expected_ident); // missing selector name. 1663 1664 KeyIdents.push_back(SelIdent); 1665 unsigned nColons = 0; 1666 if (Tok.isNot(tok::r_paren)) { 1667 while (1) { 1668 if (Tok.isNot(tok::colon)) 1669 return Diag(Tok, diag::err_expected_colon); 1670 1671 nColons++; 1672 ConsumeToken(); // Eat the ':'. 1673 if (Tok.is(tok::r_paren)) 1674 break; 1675 // Check for another keyword selector. 1676 SourceLocation Loc; 1677 SelIdent = ParseObjCSelector(Loc); 1678 KeyIdents.push_back(SelIdent); 1679 if (!SelIdent && Tok.isNot(tok::colon)) 1680 break; 1681 } 1682 } 1683 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); 1684 Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]); 1685 return Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc, LParenLoc, 1686 RParenLoc); 1687 } 1688