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