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