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