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