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