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