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