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