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