blob: 3317b88da3e903df762513df9a5cca54aa32fc42 [file] [log] [blame]
Reid Spencer5f016e22007-07-11 17:01:13 +00001//===--- ParseObjc.cpp - Objective C Parsing ------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Steve Naroff and is distributed under
6// the University of Illinois Open Source 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"
Steve Naroff4985ace2007-08-22 18:35:33 +000015#include "clang/Parse/DeclSpec.h"
Reid Spencer5f016e22007-07-11 17:01:13 +000016#include "clang/Basic/Diagnostic.h"
17#include "llvm/ADT/SmallVector.h"
18using namespace clang;
19
20
21/// ParseExternalDeclaration:
22/// external-declaration: [C99 6.9]
23/// [OBJC] objc-class-definition
24/// [OBJC] objc-class-declaration [TODO]
25/// [OBJC] objc-alias-declaration [TODO]
26/// [OBJC] objc-protocol-definition [TODO]
27/// [OBJC] objc-method-definition [TODO]
28/// [OBJC] '@' 'end' [TODO]
Steve Naroffdac269b2007-08-20 21:31:48 +000029Parser::DeclTy *Parser::ParseObjCAtDirectives() {
Reid Spencer5f016e22007-07-11 17:01:13 +000030 SourceLocation AtLoc = ConsumeToken(); // the "@"
31
Steve Naroff861cf3e2007-08-23 18:16:40 +000032 switch (Tok.getObjCKeywordID()) {
Reid Spencer5f016e22007-07-11 17:01:13 +000033 case tok::objc_class:
34 return ParseObjCAtClassDeclaration(AtLoc);
35 case tok::objc_interface:
Steve Naroffdac269b2007-08-20 21:31:48 +000036 return ParseObjCAtInterfaceDeclaration(AtLoc);
Reid Spencer5f016e22007-07-11 17:01:13 +000037 case tok::objc_protocol:
Steve Naroff7ef58fd2007-08-22 22:17:26 +000038 return ParseObjCAtProtocolDeclaration(AtLoc);
Reid Spencer5f016e22007-07-11 17:01:13 +000039 case tok::objc_implementation:
Steve Naroff3536b442007-09-06 21:24:23 +000040 return ObjcImpDecl = ParseObjCAtImplementationDeclaration(AtLoc);
Reid Spencer5f016e22007-07-11 17:01:13 +000041 case tok::objc_end:
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +000042 return ParseObjCAtEndDeclaration(AtLoc);
Reid Spencer5f016e22007-07-11 17:01:13 +000043 case tok::objc_compatibility_alias:
Fariborz Jahaniane992af02007-09-04 19:26:51 +000044 return ParseObjCAtAliasDeclaration(AtLoc);
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +000045 case tok::objc_synthesize:
46 return ParseObjCPropertySynthesize(AtLoc);
47 case tok::objc_dynamic:
48 return ParseObjCPropertyDynamic(AtLoc);
Reid Spencer5f016e22007-07-11 17:01:13 +000049 default:
50 Diag(AtLoc, diag::err_unexpected_at);
51 SkipUntil(tok::semi);
Steve Naroffdac269b2007-08-20 21:31:48 +000052 return 0;
Reid Spencer5f016e22007-07-11 17:01:13 +000053 }
54}
55
56///
57/// objc-class-declaration:
58/// '@' 'class' identifier-list ';'
59///
Steve Naroffdac269b2007-08-20 21:31:48 +000060Parser::DeclTy *Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
Reid Spencer5f016e22007-07-11 17:01:13 +000061 ConsumeToken(); // the identifier "class"
62 llvm::SmallVector<IdentifierInfo *, 8> ClassNames;
63
64 while (1) {
65 if (Tok.getKind() != tok::identifier) {
66 Diag(Tok, diag::err_expected_ident);
67 SkipUntil(tok::semi);
Steve Naroffdac269b2007-08-20 21:31:48 +000068 return 0;
Reid Spencer5f016e22007-07-11 17:01:13 +000069 }
Reid Spencer5f016e22007-07-11 17:01:13 +000070 ClassNames.push_back(Tok.getIdentifierInfo());
71 ConsumeToken();
72
73 if (Tok.getKind() != tok::comma)
74 break;
75
76 ConsumeToken();
77 }
78
79 // Consume the ';'.
80 if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
Steve Naroffdac269b2007-08-20 21:31:48 +000081 return 0;
Reid Spencer5f016e22007-07-11 17:01:13 +000082
Steve Naroff3536b442007-09-06 21:24:23 +000083 return Actions.ObjcClassDeclaration(CurScope, atLoc,
84 &ClassNames[0], ClassNames.size());
Reid Spencer5f016e22007-07-11 17:01:13 +000085}
86
Steve Naroffdac269b2007-08-20 21:31:48 +000087///
88/// objc-interface:
89/// objc-class-interface-attributes[opt] objc-class-interface
90/// objc-category-interface
91///
92/// objc-class-interface:
93/// '@' 'interface' identifier objc-superclass[opt]
94/// objc-protocol-refs[opt]
95/// objc-class-instance-variables[opt]
96/// objc-interface-decl-list
97/// @end
98///
99/// objc-category-interface:
100/// '@' 'interface' identifier '(' identifier[opt] ')'
101/// objc-protocol-refs[opt]
102/// objc-interface-decl-list
103/// @end
104///
105/// objc-superclass:
106/// ':' identifier
107///
108/// objc-class-interface-attributes:
109/// __attribute__((visibility("default")))
110/// __attribute__((visibility("hidden")))
111/// __attribute__((deprecated))
112/// __attribute__((unavailable))
113/// __attribute__((objc_exception)) - used by NSException on 64-bit
114///
115Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration(
116 SourceLocation atLoc, AttributeList *attrList) {
Steve Naroff861cf3e2007-08-23 18:16:40 +0000117 assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
Steve Naroffdac269b2007-08-20 21:31:48 +0000118 "ParseObjCAtInterfaceDeclaration(): Expected @interface");
119 ConsumeToken(); // the "interface" identifier
120
121 if (Tok.getKind() != tok::identifier) {
122 Diag(Tok, diag::err_expected_ident); // missing class or category name.
123 return 0;
124 }
125 // We have a class or category name - consume it.
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000126 IdentifierInfo *nameId = Tok.getIdentifierInfo();
Steve Naroffdac269b2007-08-20 21:31:48 +0000127 SourceLocation nameLoc = ConsumeToken();
128
Steve Naroff527fe232007-08-23 19:56:30 +0000129 if (Tok.getKind() == tok::l_paren) { // we have a category.
Steve Naroffdac269b2007-08-20 21:31:48 +0000130 SourceLocation lparenLoc = ConsumeParen();
131 SourceLocation categoryLoc, rparenLoc;
132 IdentifierInfo *categoryId = 0;
Fariborz Jahanianfd225cc2007-09-18 20:26:58 +0000133 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
Steve Naroffdac269b2007-08-20 21:31:48 +0000134
Steve Naroff527fe232007-08-23 19:56:30 +0000135 // For ObjC2, the category name is optional (not an error).
Steve Naroffdac269b2007-08-20 21:31:48 +0000136 if (Tok.getKind() == tok::identifier) {
137 categoryId = Tok.getIdentifierInfo();
138 categoryLoc = ConsumeToken();
Steve Naroff527fe232007-08-23 19:56:30 +0000139 } else if (!getLang().ObjC2) {
140 Diag(Tok, diag::err_expected_ident); // missing category name.
141 return 0;
Steve Naroffdac269b2007-08-20 21:31:48 +0000142 }
143 if (Tok.getKind() != tok::r_paren) {
144 Diag(Tok, diag::err_expected_rparen);
145 SkipUntil(tok::r_paren, false); // don't stop at ';'
146 return 0;
147 }
148 rparenLoc = ConsumeParen();
149 // Next, we need to check for any protocol references.
150 if (Tok.getKind() == tok::less) {
Steve Narofff28b2642007-09-05 23:30:30 +0000151 if (ParseObjCProtocolReferences(ProtocolRefs))
Steve Naroffdac269b2007-08-20 21:31:48 +0000152 return 0;
153 }
154 if (attrList) // categories don't support attributes.
155 Diag(Tok, diag::err_objc_no_attributes_on_category);
156
Fariborz Jahanianfd225cc2007-09-18 20:26:58 +0000157 DeclTy *CategoryType = Actions.ObjcStartCatInterface(atLoc,
158 nameId, nameLoc,
159 categoryId, categoryLoc,
160 &ProtocolRefs[0],
161 ProtocolRefs.size());
162
163 ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword);
Steve Naroffdac269b2007-08-20 21:31:48 +0000164
Steve Naroff294494e2007-08-22 16:35:03 +0000165 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
Steve Naroff861cf3e2007-08-23 18:16:40 +0000166 if (Tok.isObjCAtKeyword(tok::objc_end)) {
Steve Naroff294494e2007-08-22 16:35:03 +0000167 ConsumeToken(); // the "end" identifier
Steve Naroffdac269b2007-08-20 21:31:48 +0000168 return 0;
169 }
Steve Naroff294494e2007-08-22 16:35:03 +0000170 Diag(Tok, diag::err_objc_missing_end);
Steve Naroffdac269b2007-08-20 21:31:48 +0000171 return 0;
172 }
173 // Parse a class interface.
174 IdentifierInfo *superClassId = 0;
175 SourceLocation superClassLoc;
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000176
Steve Naroffdac269b2007-08-20 21:31:48 +0000177 if (Tok.getKind() == tok::colon) { // a super class is specified.
178 ConsumeToken();
179 if (Tok.getKind() != tok::identifier) {
180 Diag(Tok, diag::err_expected_ident); // missing super class name.
181 return 0;
182 }
183 superClassId = Tok.getIdentifierInfo();
184 superClassLoc = ConsumeToken();
185 }
186 // Next, we need to check for any protocol references.
Steve Narofff28b2642007-09-05 23:30:30 +0000187 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
Steve Naroffdac269b2007-08-20 21:31:48 +0000188 if (Tok.getKind() == tok::less) {
Steve Narofff28b2642007-09-05 23:30:30 +0000189 if (ParseObjCProtocolReferences(ProtocolRefs))
Steve Naroffdac269b2007-08-20 21:31:48 +0000190 return 0;
191 }
Fariborz Jahanianccb4f312007-09-25 18:38:09 +0000192 DeclTy *ClsType = Actions.ObjcStartClassInterface(CurScope,
193 atLoc, nameId, nameLoc,
Steve Narofff28b2642007-09-05 23:30:30 +0000194 superClassId, superClassLoc, &ProtocolRefs[0],
195 ProtocolRefs.size(), attrList);
196
Steve Naroffdac269b2007-08-20 21:31:48 +0000197 if (Tok.getKind() == tok::l_brace)
Steve Naroff3536b442007-09-06 21:24:23 +0000198 ParseObjCClassInstanceVariables(ClsType);
Steve Naroffdac269b2007-08-20 21:31:48 +0000199
Fariborz Jahanian25e077d2007-09-17 21:07:36 +0000200 ParseObjCInterfaceDeclList(ClsType, tok::objc_interface);
Steve Naroff294494e2007-08-22 16:35:03 +0000201
202 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
Steve Naroff861cf3e2007-08-23 18:16:40 +0000203 if (Tok.isObjCAtKeyword(tok::objc_end)) {
Steve Naroff294494e2007-08-22 16:35:03 +0000204 ConsumeToken(); // the "end" identifier
Steve Naroff2bd42fa2007-09-10 20:51:04 +0000205 return ClsType;
Steve Naroffdac269b2007-08-20 21:31:48 +0000206 }
Steve Naroff294494e2007-08-22 16:35:03 +0000207 Diag(Tok, diag::err_objc_missing_end);
Steve Naroffdac269b2007-08-20 21:31:48 +0000208 return 0;
209}
210
211/// objc-interface-decl-list:
212/// empty
Steve Naroffdac269b2007-08-20 21:31:48 +0000213/// objc-interface-decl-list objc-property-decl [OBJC2]
Steve Naroff294494e2007-08-22 16:35:03 +0000214/// objc-interface-decl-list objc-method-requirement [OBJC2]
Steve Naroff3536b442007-09-06 21:24:23 +0000215/// objc-interface-decl-list objc-method-proto ';'
Steve Naroffdac269b2007-08-20 21:31:48 +0000216/// objc-interface-decl-list declaration
217/// objc-interface-decl-list ';'
218///
Steve Naroff294494e2007-08-22 16:35:03 +0000219/// objc-method-requirement: [OBJC2]
220/// @required
221/// @optional
222///
Fariborz Jahanian25e077d2007-09-17 21:07:36 +0000223void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl,
224 tok::ObjCKeywordKind contextKey) {
Fariborz Jahaniane3a2ca72007-09-10 20:33:04 +0000225 llvm::SmallVector<DeclTy*, 32> allMethods;
Fariborz Jahanian00933592007-09-18 00:25:23 +0000226 tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
Steve Naroff294494e2007-08-22 16:35:03 +0000227 while (1) {
228 if (Tok.getKind() == tok::at) {
229 SourceLocation AtLoc = ConsumeToken(); // the "@"
Steve Naroff861cf3e2007-08-23 18:16:40 +0000230 tok::ObjCKeywordKind ocKind = Tok.getObjCKeywordID();
Steve Naroff294494e2007-08-22 16:35:03 +0000231
232 if (ocKind == tok::objc_end) { // terminate list
Fariborz Jahaniane3a2ca72007-09-10 20:33:04 +0000233 break;
Steve Naroff294494e2007-08-22 16:35:03 +0000234 } else if (ocKind == tok::objc_required) { // protocols only
235 ConsumeToken();
Fariborz Jahanian00933592007-09-18 00:25:23 +0000236 MethodImplKind = ocKind;
Fariborz Jahanian25e077d2007-09-17 21:07:36 +0000237 if (contextKey != tok::objc_protocol)
238 Diag(AtLoc, diag::err_objc_protocol_required);
Steve Naroff294494e2007-08-22 16:35:03 +0000239 } else if (ocKind == tok::objc_optional) { // protocols only
240 ConsumeToken();
Fariborz Jahanian00933592007-09-18 00:25:23 +0000241 MethodImplKind = ocKind;
Fariborz Jahanian25e077d2007-09-17 21:07:36 +0000242 if (contextKey != tok::objc_protocol)
243 Diag(AtLoc, diag::err_objc_protocol_optional);
Steve Naroff294494e2007-08-22 16:35:03 +0000244 } else if (ocKind == tok::objc_property) {
Fariborz Jahaniane55cd002007-09-12 18:23:47 +0000245 ParseObjCPropertyDecl(interfaceDecl);
Steve Naroff294494e2007-08-22 16:35:03 +0000246 continue;
247 } else {
248 Diag(Tok, diag::err_objc_illegal_interface_qual);
249 ConsumeToken();
250 }
251 }
252 if (Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) {
Fariborz Jahanian00933592007-09-18 00:25:23 +0000253 DeclTy *methodPrototype = ParseObjCMethodPrototype(interfaceDecl, MethodImplKind);
Fariborz Jahanian25e077d2007-09-17 21:07:36 +0000254 allMethods.push_back(methodPrototype);
Steve Naroff3536b442007-09-06 21:24:23 +0000255 // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
256 // method definitions.
Steve Naroffd16245b2007-09-17 15:07:43 +0000257 ExpectAndConsume(tok::semi, diag::err_expected_semi_after,"method proto");
Steve Naroff294494e2007-08-22 16:35:03 +0000258 continue;
259 }
260 if (Tok.getKind() == tok::semi)
261 ConsumeToken();
262 else if (Tok.getKind() == tok::eof)
Fariborz Jahaniane3a2ca72007-09-10 20:33:04 +0000263 break;
Steve Narofff28b2642007-09-05 23:30:30 +0000264 else {
Steve Naroff4985ace2007-08-22 18:35:33 +0000265 // FIXME: as the name implies, this rule allows function definitions.
266 // We could pass a flag or check for functions during semantic analysis.
Steve Naroff3536b442007-09-06 21:24:23 +0000267 ParseDeclarationOrFunctionDefinition();
Steve Narofff28b2642007-09-05 23:30:30 +0000268 }
Steve Naroff294494e2007-08-22 16:35:03 +0000269 }
Fariborz Jahaniane3a2ca72007-09-10 20:33:04 +0000270 /// Insert collected methods declarations into the @interface object.
Steve Naroffd16245b2007-09-17 15:07:43 +0000271 Actions.ObjcAddMethodsToClass(interfaceDecl,&allMethods[0],allMethods.size());
Fariborz Jahaniane3a2ca72007-09-10 20:33:04 +0000272 return;
Steve Naroff294494e2007-08-22 16:35:03 +0000273}
274
Fariborz Jahaniand0f97d12007-08-31 16:11:31 +0000275/// Parse property attribute declarations.
276///
277/// property-attr-decl: '(' property-attrlist ')'
278/// property-attrlist:
279/// property-attribute
280/// property-attrlist ',' property-attribute
281/// property-attribute:
282/// getter '=' identifier
283/// setter '=' identifier ':'
284/// readonly
285/// readwrite
286/// assign
287/// retain
288/// copy
289/// nonatomic
290///
291void Parser::ParseObjCPropertyAttribute (DeclTy *interfaceDecl) {
292 SourceLocation loc = ConsumeParen(); // consume '('
293 while (isObjCPropertyAttribute()) {
294 const IdentifierInfo *II = Tok.getIdentifierInfo();
295 // getter/setter require extra treatment.
296 if (II == ObjcPropertyAttrs[objc_getter] ||
297 II == ObjcPropertyAttrs[objc_setter]) {
298 // skip getter/setter part.
299 SourceLocation loc = ConsumeToken();
300 if (Tok.getKind() == tok::equal) {
301 loc = ConsumeToken();
302 if (Tok.getKind() == tok::identifier) {
303 if (II == ObjcPropertyAttrs[objc_setter]) {
304 loc = ConsumeToken(); // consume method name
305 if (Tok.getKind() != tok::colon) {
306 Diag(loc, diag::err_expected_colon);
307 SkipUntil(tok::r_paren,true,true);
308 break;
309 }
310 }
311 }
312 else {
313 Diag(loc, diag::err_expected_ident);
314 SkipUntil(tok::r_paren,true,true);
315 break;
316 }
317 }
318 else {
319 Diag(loc, diag::err_objc_expected_equal);
320 SkipUntil(tok::r_paren,true,true);
321 break;
322 }
323 }
324 ConsumeToken(); // consume last attribute token
325 if (Tok.getKind() == tok::comma) {
326 loc = ConsumeToken();
327 continue;
328 }
329 if (Tok.getKind() == tok::r_paren)
330 break;
331 Diag(loc, diag::err_expected_rparen);
332 SkipUntil(tok::semi);
333 return;
334 }
335 if (Tok.getKind() == tok::r_paren)
336 ConsumeParen();
337 else {
338 Diag(loc, diag::err_objc_expected_property_attr);
339 SkipUntil(tok::r_paren); // recover from error inside attribute list
340 }
341}
342
343/// Main routine to parse property declaration.
344///
345/// @property property-attr-decl[opt] property-component-decl ';'
346///
347void Parser::ParseObjCPropertyDecl(DeclTy *interfaceDecl) {
348 assert(Tok.isObjCAtKeyword(tok::objc_property) &&
349 "ParseObjCPropertyDecl(): Expected @property");
350 ConsumeToken(); // the "property" identifier
351 // Parse property attribute list, if any.
352 if (Tok.getKind() == tok::l_paren) {
353 // property has attribute list.
354 ParseObjCPropertyAttribute(0/*FIXME*/);
355 }
356 // Parse declaration portion of @property.
357 llvm::SmallVector<DeclTy*, 32> PropertyDecls;
358 ParseStructDeclaration(interfaceDecl, PropertyDecls);
359 if (Tok.getKind() == tok::semi)
360 ConsumeToken();
361 else {
362 Diag(Tok, diag::err_expected_semi_decl_list);
363 SkipUntil(tok::r_brace, true, true);
364 }
Reid Spencer5f016e22007-07-11 17:01:13 +0000365}
Steve Naroffdac269b2007-08-20 21:31:48 +0000366
Steve Naroff3536b442007-09-06 21:24:23 +0000367/// objc-method-proto:
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +0000368/// objc-instance-method objc-method-decl objc-method-attributes[opt]
Steve Naroff3536b442007-09-06 21:24:23 +0000369/// objc-class-method objc-method-decl objc-method-attributes[opt]
Steve Naroff294494e2007-08-22 16:35:03 +0000370///
371/// objc-instance-method: '-'
372/// objc-class-method: '+'
373///
Steve Naroff4985ace2007-08-22 18:35:33 +0000374/// objc-method-attributes: [OBJC2]
375/// __attribute__((deprecated))
376///
Fariborz Jahanian00933592007-09-18 00:25:23 +0000377Parser::DeclTy *Parser::ParseObjCMethodPrototype(DeclTy *IDecl,
378 tok::ObjCKeywordKind MethodImplKind) {
Steve Naroff294494e2007-08-22 16:35:03 +0000379 assert((Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) &&
380 "expected +/-");
381
382 tok::TokenKind methodType = Tok.getKind();
383 SourceLocation methodLoc = ConsumeToken();
384
Fariborz Jahanian00933592007-09-18 00:25:23 +0000385 DeclTy *MDecl = ParseObjCMethodDecl(methodType, methodLoc, MethodImplKind);
Steve Naroff3536b442007-09-06 21:24:23 +0000386 // Since this rule is used for both method declarations and definitions,
Steve Naroff2bd42fa2007-09-10 20:51:04 +0000387 // the caller is (optionally) responsible for consuming the ';'.
Steve Narofff28b2642007-09-05 23:30:30 +0000388 return MDecl;
Steve Naroff294494e2007-08-22 16:35:03 +0000389}
390
391/// objc-selector:
392/// identifier
393/// one of
394/// enum struct union if else while do for switch case default
395/// break continue return goto asm sizeof typeof __alignof
396/// unsigned long const short volatile signed restrict _Complex
397/// in out inout bycopy byref oneway int char float double void _Bool
398///
399IdentifierInfo *Parser::ParseObjCSelector() {
400 tok::TokenKind tKind = Tok.getKind();
401 IdentifierInfo *II = 0;
Fariborz Jahaniand0649512007-09-27 19:52:15 +0000402 switch (tKind) {
403 case tok::identifier:
404 case tok::kw_typeof:
405 case tok::kw___alignof:
406 case tok::kw_auto:
407 case tok::kw_break:
408 case tok::kw_case:
409 case tok::kw_char:
410 case tok::kw_const:
411 case tok::kw_continue:
412 case tok::kw_default:
413 case tok::kw_do:
414 case tok::kw_double:
415 case tok::kw_else:
416 case tok::kw_enum:
417 case tok::kw_extern:
418 case tok::kw_float:
419 case tok::kw_for:
420 case tok::kw_goto:
421 case tok::kw_if:
422 case tok::kw_inline:
423 case tok::kw_int:
424 case tok::kw_long:
425 case tok::kw_register:
426 case tok::kw_restrict:
427 case tok::kw_return:
428 case tok::kw_short:
429 case tok::kw_signed:
430 case tok::kw_sizeof:
431 case tok::kw_static:
432 case tok::kw_struct:
433 case tok::kw_switch:
434 case tok::kw_typedef:
435 case tok::kw_union:
436 case tok::kw_unsigned:
437 case tok::kw_void:
438 case tok::kw_volatile:
439 case tok::kw_while:
440 case tok::kw__Bool:
441 case tok::kw__Complex:
442 II = Tok.getIdentifierInfo();
443 ConsumeToken();
444 default:
445 break;
446 }
Steve Naroff294494e2007-08-22 16:35:03 +0000447
Steve Naroff294494e2007-08-22 16:35:03 +0000448 return II;
449}
450
Steve Naroff4fa7afd2007-08-22 23:18:22 +0000451/// objc-type-qualifier: one of
452/// in out inout bycopy byref oneway
453///
Steve Naroff4fa7afd2007-08-22 23:18:22 +0000454bool Parser::isObjCTypeQualifier() {
455 if (Tok.getKind() == tok::identifier) {
Chris Lattner34870da2007-08-29 22:54:08 +0000456 const IdentifierInfo *II = Tok.getIdentifierInfo();
457 for (unsigned i = 0; i < objc_NumQuals; ++i)
458 if (II == ObjcTypeQuals[i]) return true;
Steve Naroff4fa7afd2007-08-22 23:18:22 +0000459 }
460 return false;
461}
462
Fariborz Jahaniand0f97d12007-08-31 16:11:31 +0000463/// property-attrlist: one of
464/// readonly getter setter assign retain copy nonatomic
465///
466bool Parser::isObjCPropertyAttribute() {
467 if (Tok.getKind() == tok::identifier) {
468 const IdentifierInfo *II = Tok.getIdentifierInfo();
469 for (unsigned i = 0; i < objc_NumAttrs; ++i)
470 if (II == ObjcPropertyAttrs[i]) return true;
471 }
472 return false;
473}
474
Steve Naroff294494e2007-08-22 16:35:03 +0000475/// objc-type-name:
476/// '(' objc-type-qualifiers[opt] type-name ')'
477/// '(' objc-type-qualifiers[opt] ')'
478///
479/// objc-type-qualifiers:
480/// objc-type-qualifier
481/// objc-type-qualifiers objc-type-qualifier
482///
Steve Narofff28b2642007-09-05 23:30:30 +0000483Parser::TypeTy *Parser::ParseObjCTypeName() {
Steve Naroff294494e2007-08-22 16:35:03 +0000484 assert(Tok.getKind() == tok::l_paren && "expected (");
485
486 SourceLocation LParenLoc = ConsumeParen(), RParenLoc;
Chris Lattner271f1a62007-09-27 15:15:46 +0000487 TypeTy *Ty = 0;
Steve Naroff294494e2007-08-22 16:35:03 +0000488
Steve Naroff4fa7afd2007-08-22 23:18:22 +0000489 while (isObjCTypeQualifier())
490 ConsumeToken();
491
Steve Naroff294494e2007-08-22 16:35:03 +0000492 if (isTypeSpecifierQualifier()) {
Steve Narofff28b2642007-09-05 23:30:30 +0000493 Ty = ParseTypeName();
494 // FIXME: back when Sema support is in place...
495 // assert(Ty && "Parser::ParseObjCTypeName(): missing type");
Steve Naroff294494e2007-08-22 16:35:03 +0000496 }
497 if (Tok.getKind() != tok::r_paren) {
498 MatchRHSPunctuation(tok::r_paren, LParenLoc);
Steve Narofff28b2642007-09-05 23:30:30 +0000499 return 0; // FIXME: decide how we want to handle this error...
Steve Naroff294494e2007-08-22 16:35:03 +0000500 }
501 RParenLoc = ConsumeParen();
Steve Narofff28b2642007-09-05 23:30:30 +0000502 return Ty;
Steve Naroff294494e2007-08-22 16:35:03 +0000503}
504
Steve Naroffbcfb06a2007-09-28 22:22:11 +0000505Selector Parser::ObjcGetUnarySelector(IdentifierInfo *unarySel)
Steve Naroff68d331a2007-09-27 14:38:14 +0000506{
Steve Naroffbcfb06a2007-09-28 22:22:11 +0000507 return Selector(unarySel, 0);
Steve Naroff68d331a2007-09-27 14:38:14 +0000508}
509
Steve Naroffbcfb06a2007-09-28 22:22:11 +0000510Selector Parser::ObjcGetKeywordSelector(
511 llvm::SmallVectorImpl<IdentifierInfo *> &IIV)
512{
513 if (IIV.size() == 1)
514 return Selector(IIV[0], 1);
515
516 llvm::FoldingSet<MultiKeywordSelector> &SelTab = PP.getSelectorTable();
517
Steve Naroff68d331a2007-09-27 14:38:14 +0000518 // Unique selector, to guarantee there is one per name.
519 llvm::FoldingSetNodeID ID;
Steve Naroffbcfb06a2007-09-28 22:22:11 +0000520 MultiKeywordSelector::Profile(ID, &IIV[0], IIV.size());
Steve Naroff68d331a2007-09-27 14:38:14 +0000521
522 void *InsertPos = 0;
Steve Naroffbcfb06a2007-09-28 22:22:11 +0000523 if (MultiKeywordSelector *SI = SelTab.FindNodeOrInsertPos(ID, InsertPos)) {
524 return Selector(SI);
525 }
526 // MultiKeywordSelector objects are not allocated with new because they have a
Steve Naroff68d331a2007-09-27 14:38:14 +0000527 // variable size array (for parameter types) at the end of them.
Steve Naroffbcfb06a2007-09-28 22:22:11 +0000528 MultiKeywordSelector *SI =
529 (MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) +
530 IIV.size()*sizeof(IdentifierInfo *));
531 new (SI) MultiKeywordSelector(IIV.size(), &IIV[0]);
Steve Naroff68d331a2007-09-27 14:38:14 +0000532 SelTab.InsertNode(SI, InsertPos);
Steve Naroffbcfb06a2007-09-28 22:22:11 +0000533 return Selector(SI);
Steve Naroff68d331a2007-09-27 14:38:14 +0000534}
535
Steve Naroff294494e2007-08-22 16:35:03 +0000536/// objc-method-decl:
537/// objc-selector
Steve Naroff4985ace2007-08-22 18:35:33 +0000538/// objc-keyword-selector objc-parmlist[opt]
Steve Naroff294494e2007-08-22 16:35:03 +0000539/// objc-type-name objc-selector
Steve Naroff4985ace2007-08-22 18:35:33 +0000540/// objc-type-name objc-keyword-selector objc-parmlist[opt]
Steve Naroff294494e2007-08-22 16:35:03 +0000541///
542/// objc-keyword-selector:
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000543/// objc-keyword-decl
Steve Naroff294494e2007-08-22 16:35:03 +0000544/// objc-keyword-selector objc-keyword-decl
545///
546/// objc-keyword-decl:
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000547/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
548/// objc-selector ':' objc-keyword-attributes[opt] identifier
549/// ':' objc-type-name objc-keyword-attributes[opt] identifier
550/// ':' objc-keyword-attributes[opt] identifier
Steve Naroff294494e2007-08-22 16:35:03 +0000551///
Steve Naroff4985ace2007-08-22 18:35:33 +0000552/// objc-parmlist:
553/// objc-parms objc-ellipsis[opt]
Steve Naroff294494e2007-08-22 16:35:03 +0000554///
Steve Naroff4985ace2007-08-22 18:35:33 +0000555/// objc-parms:
556/// objc-parms , parameter-declaration
Steve Naroff294494e2007-08-22 16:35:03 +0000557///
Steve Naroff4985ace2007-08-22 18:35:33 +0000558/// objc-ellipsis:
Steve Naroff294494e2007-08-22 16:35:03 +0000559/// , ...
560///
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000561/// objc-keyword-attributes: [OBJC2]
562/// __attribute__((unused))
563///
Steve Naroff68d331a2007-09-27 14:38:14 +0000564Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType,
565 SourceLocation mLoc,
566 tok::ObjCKeywordKind MethodImplKind)
567{
Steve Narofff28b2642007-09-05 23:30:30 +0000568 TypeTy *ReturnType = 0;
Fariborz Jahaniane3a2ca72007-09-10 20:33:04 +0000569 AttributeList *methodAttrs = 0;
Steve Narofff28b2642007-09-05 23:30:30 +0000570
Steve Naroff4985ace2007-08-22 18:35:33 +0000571 // Parse the return type.
Steve Naroff294494e2007-08-22 16:35:03 +0000572 if (Tok.getKind() == tok::l_paren)
Steve Narofff28b2642007-09-05 23:30:30 +0000573 ReturnType = ParseObjCTypeName();
Steve Naroff4985ace2007-08-22 18:35:33 +0000574 IdentifierInfo *selIdent = ParseObjCSelector();
Steve Narofff28b2642007-09-05 23:30:30 +0000575
Steve Naroff68d331a2007-09-27 14:38:14 +0000576 llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
577 llvm::SmallVector<Action::TypeTy *, 12> KeyTypes;
578 llvm::SmallVector<IdentifierInfo *, 12> ArgNames;
579
Steve Naroff4985ace2007-08-22 18:35:33 +0000580 if (Tok.getKind() == tok::colon) {
Steve Naroff68d331a2007-09-27 14:38:14 +0000581 Action::TypeTy *TypeInfo;
Steve Narofff28b2642007-09-05 23:30:30 +0000582
Steve Naroff4985ace2007-08-22 18:35:33 +0000583 while (1) {
Steve Naroff68d331a2007-09-27 14:38:14 +0000584 KeyIdents.push_back(selIdent);
Steve Narofff28b2642007-09-05 23:30:30 +0000585
Steve Naroff4985ace2007-08-22 18:35:33 +0000586 // Each iteration parses a single keyword argument.
587 if (Tok.getKind() != tok::colon) {
588 Diag(Tok, diag::err_expected_colon);
589 break;
590 }
Steve Naroff68d331a2007-09-27 14:38:14 +0000591 ConsumeToken(); // Eat the ':'.
Steve Naroff4985ace2007-08-22 18:35:33 +0000592 if (Tok.getKind() == tok::l_paren) // Parse the argument type.
Steve Naroff68d331a2007-09-27 14:38:14 +0000593 TypeInfo = ParseObjCTypeName();
594 else
595 TypeInfo = 0;
596 KeyTypes.push_back(TypeInfo);
597
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000598 // If attributes exist before the argument name, parse them.
Steve Naroff527fe232007-08-23 19:56:30 +0000599 if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
Steve Naroff68d331a2007-09-27 14:38:14 +0000600 ParseAttributes(); // FIXME: pass attributes through.
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000601
Steve Naroff4985ace2007-08-22 18:35:33 +0000602 if (Tok.getKind() != tok::identifier) {
603 Diag(Tok, diag::err_expected_ident); // missing argument name.
604 break;
605 }
Steve Naroff68d331a2007-09-27 14:38:14 +0000606 ArgNames.push_back(Tok.getIdentifierInfo());
Steve Naroff4985ace2007-08-22 18:35:33 +0000607 ConsumeToken(); // Eat the identifier.
Steve Narofff28b2642007-09-05 23:30:30 +0000608
Steve Naroff37387c92007-09-17 20:25:27 +0000609 // Check for another keyword selector.
Steve Narofff28b2642007-09-05 23:30:30 +0000610 selIdent = ParseObjCSelector();
611 if (!selIdent && Tok.getKind() != tok::colon)
Steve Naroff4985ace2007-08-22 18:35:33 +0000612 break;
613 // We have a selector or a colon, continue parsing.
614 }
615 // Parse the (optional) parameter list.
616 while (Tok.getKind() == tok::comma) {
617 ConsumeToken();
618 if (Tok.getKind() == tok::ellipsis) {
619 ConsumeToken();
620 break;
621 }
Fariborz Jahanian0ccb27d2007-09-05 19:52:07 +0000622 // Parse the c-style argument declaration-specifier.
623 DeclSpec DS;
624 ParseDeclarationSpecifiers(DS);
625 // Parse the declarator.
626 Declarator ParmDecl(DS, Declarator::PrototypeContext);
627 ParseDeclarator(ParmDecl);
Steve Naroff4985ace2007-08-22 18:35:33 +0000628 }
Steve Narofff28b2642007-09-05 23:30:30 +0000629 // FIXME: Add support for optional parmameter list...
Fariborz Jahaniane3a2ca72007-09-10 20:33:04 +0000630 // If attributes exist after the method, parse them.
631 if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
632 methodAttrs = ParseAttributes();
Steve Naroff68d331a2007-09-27 14:38:14 +0000633
Steve Naroffbcfb06a2007-09-28 22:22:11 +0000634 Selector Sel = ObjcGetKeywordSelector(KeyIdents);
635 return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, Sel,
Steve Naroff68d331a2007-09-27 14:38:14 +0000636 &KeyTypes[0], &ArgNames[0],
Fariborz Jahanian00933592007-09-18 00:25:23 +0000637 methodAttrs, MethodImplKind);
Steve Naroff4985ace2007-08-22 18:35:33 +0000638 } else if (!selIdent) {
639 Diag(Tok, diag::err_expected_ident); // missing selector name.
640 }
Fariborz Jahaniane3a2ca72007-09-10 20:33:04 +0000641 // If attributes exist after the method, parse them.
642 if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
643 methodAttrs = ParseAttributes();
644
Steve Naroffbcfb06a2007-09-28 22:22:11 +0000645 Selector Sel = ObjcGetUnarySelector(selIdent);
646 return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, Sel,
Steve Naroff68d331a2007-09-27 14:38:14 +0000647 0, 0, methodAttrs, MethodImplKind);
Steve Naroff294494e2007-08-22 16:35:03 +0000648}
649
Steve Naroffdac269b2007-08-20 21:31:48 +0000650/// objc-protocol-refs:
651/// '<' identifier-list '>'
652///
Steve Narofff28b2642007-09-05 23:30:30 +0000653bool Parser::ParseObjCProtocolReferences(
654 llvm::SmallVectorImpl<IdentifierInfo*> &ProtocolRefs) {
Steve Naroffdac269b2007-08-20 21:31:48 +0000655 assert(Tok.getKind() == tok::less && "expected <");
656
657 ConsumeToken(); // the "<"
Steve Naroffdac269b2007-08-20 21:31:48 +0000658
659 while (1) {
660 if (Tok.getKind() != tok::identifier) {
661 Diag(Tok, diag::err_expected_ident);
662 SkipUntil(tok::greater);
663 return true;
664 }
665 ProtocolRefs.push_back(Tok.getIdentifierInfo());
666 ConsumeToken();
667
668 if (Tok.getKind() != tok::comma)
669 break;
670 ConsumeToken();
671 }
672 // Consume the '>'.
673 return ExpectAndConsume(tok::greater, diag::err_expected_greater);
674}
675
676/// objc-class-instance-variables:
677/// '{' objc-instance-variable-decl-list[opt] '}'
678///
679/// objc-instance-variable-decl-list:
680/// objc-visibility-spec
681/// objc-instance-variable-decl ';'
682/// ';'
683/// objc-instance-variable-decl-list objc-visibility-spec
684/// objc-instance-variable-decl-list objc-instance-variable-decl ';'
685/// objc-instance-variable-decl-list ';'
686///
687/// objc-visibility-spec:
688/// @private
689/// @protected
690/// @public
Steve Naroffddbff782007-08-21 21:17:12 +0000691/// @package [OBJC2]
Steve Naroffdac269b2007-08-20 21:31:48 +0000692///
693/// objc-instance-variable-decl:
694/// struct-declaration
695///
Steve Naroff3536b442007-09-06 21:24:23 +0000696void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl) {
Steve Naroffddbff782007-08-21 21:17:12 +0000697 assert(Tok.getKind() == tok::l_brace && "expected {");
Steve Naroff3536b442007-09-06 21:24:23 +0000698 llvm::SmallVector<DeclTy*, 16> IvarDecls;
Fariborz Jahanian7d6402f2007-09-13 20:56:13 +0000699 llvm::SmallVector<DeclTy*, 32> AllIvarDecls;
700 llvm::SmallVector<tok::ObjCKeywordKind, 32> AllVisibilities;
Steve Naroffddbff782007-08-21 21:17:12 +0000701
702 SourceLocation LBraceLoc = ConsumeBrace(); // the "{"
Steve Naroffddbff782007-08-21 21:17:12 +0000703
Fariborz Jahanian7d6402f2007-09-13 20:56:13 +0000704 tok::ObjCKeywordKind visibility = tok::objc_private;
Steve Naroffddbff782007-08-21 21:17:12 +0000705 // While we still have something to read, read the instance variables.
706 while (Tok.getKind() != tok::r_brace &&
707 Tok.getKind() != tok::eof) {
708 // Each iteration of this loop reads one objc-instance-variable-decl.
709
710 // Check for extraneous top-level semicolon.
711 if (Tok.getKind() == tok::semi) {
712 Diag(Tok, diag::ext_extra_struct_semi);
713 ConsumeToken();
714 continue;
715 }
716 // Set the default visibility to private.
Steve Naroffddbff782007-08-21 21:17:12 +0000717 if (Tok.getKind() == tok::at) { // parse objc-visibility-spec
718 ConsumeToken(); // eat the @ sign
Steve Naroff861cf3e2007-08-23 18:16:40 +0000719 switch (Tok.getObjCKeywordID()) {
Steve Naroffddbff782007-08-21 21:17:12 +0000720 case tok::objc_private:
721 case tok::objc_public:
722 case tok::objc_protected:
723 case tok::objc_package:
Steve Naroff861cf3e2007-08-23 18:16:40 +0000724 visibility = Tok.getObjCKeywordID();
Steve Naroffddbff782007-08-21 21:17:12 +0000725 ConsumeToken();
726 continue;
727 default:
728 Diag(Tok, diag::err_objc_illegal_visibility_spec);
729 ConsumeToken();
730 continue;
731 }
732 }
733 ParseStructDeclaration(interfaceDecl, IvarDecls);
Fariborz Jahanian7d6402f2007-09-13 20:56:13 +0000734 for (unsigned i = 0; i < IvarDecls.size(); i++) {
735 AllIvarDecls.push_back(IvarDecls[i]);
736 AllVisibilities.push_back(visibility);
737 }
Steve Naroff3536b442007-09-06 21:24:23 +0000738 IvarDecls.clear();
739
Steve Naroffddbff782007-08-21 21:17:12 +0000740 if (Tok.getKind() == tok::semi) {
741 ConsumeToken();
742 } else if (Tok.getKind() == tok::r_brace) {
743 Diag(Tok.getLocation(), diag::ext_expected_semi_decl_list);
744 break;
745 } else {
746 Diag(Tok, diag::err_expected_semi_decl_list);
747 // Skip to end of block or statement
748 SkipUntil(tok::r_brace, true, true);
749 }
750 }
Fariborz Jahanian7d6402f2007-09-13 20:56:13 +0000751 if (AllIvarDecls.size()) { // Check for {} - no ivars in braces
Steve Naroff08d92e42007-09-15 18:49:24 +0000752 Actions.ActOnFields(LBraceLoc, interfaceDecl,
753 &AllIvarDecls[0], AllIvarDecls.size(),
754 &AllVisibilities[0]);
Fariborz Jahanian7d6402f2007-09-13 20:56:13 +0000755 }
Steve Naroffddbff782007-08-21 21:17:12 +0000756 MatchRHSPunctuation(tok::r_brace, LBraceLoc);
757 return;
Reid Spencer5f016e22007-07-11 17:01:13 +0000758}
Steve Naroffdac269b2007-08-20 21:31:48 +0000759
760/// objc-protocol-declaration:
761/// objc-protocol-definition
762/// objc-protocol-forward-reference
763///
764/// objc-protocol-definition:
765/// @protocol identifier
766/// objc-protocol-refs[opt]
Steve Naroff3536b442007-09-06 21:24:23 +0000767/// objc-interface-decl-list
Steve Naroffdac269b2007-08-20 21:31:48 +0000768/// @end
769///
770/// objc-protocol-forward-reference:
771/// @protocol identifier-list ';'
772///
773/// "@protocol identifier ;" should be resolved as "@protocol
Steve Naroff3536b442007-09-06 21:24:23 +0000774/// identifier-list ;": objc-interface-decl-list may not start with a
Steve Naroffdac269b2007-08-20 21:31:48 +0000775/// semicolon in the first alternative if objc-protocol-refs are omitted.
776
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000777Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) {
Steve Naroff861cf3e2007-08-23 18:16:40 +0000778 assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000779 "ParseObjCAtProtocolDeclaration(): Expected @protocol");
780 ConsumeToken(); // the "protocol" identifier
781
782 if (Tok.getKind() != tok::identifier) {
783 Diag(Tok, diag::err_expected_ident); // missing protocol name.
784 return 0;
785 }
786 // Save the protocol name, then consume it.
787 IdentifierInfo *protocolName = Tok.getIdentifierInfo();
788 SourceLocation nameLoc = ConsumeToken();
789
Fariborz Jahanian894c57f2007-09-21 15:40:54 +0000790 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
791 if (Tok.getKind() == tok::semi) { // forward declaration of one protocol.
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000792 ConsumeToken();
Fariborz Jahanian894c57f2007-09-21 15:40:54 +0000793 ProtocolRefs.push_back(protocolName);
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000794 }
795 if (Tok.getKind() == tok::comma) { // list of forward declarations.
796 // Parse the list of forward declarations.
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000797 ProtocolRefs.push_back(protocolName);
798
799 while (1) {
800 ConsumeToken(); // the ','
801 if (Tok.getKind() != tok::identifier) {
802 Diag(Tok, diag::err_expected_ident);
803 SkipUntil(tok::semi);
804 return 0;
805 }
806 ProtocolRefs.push_back(Tok.getIdentifierInfo());
807 ConsumeToken(); // the identifier
808
809 if (Tok.getKind() != tok::comma)
810 break;
811 }
812 // Consume the ';'.
813 if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
814 return 0;
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000815 }
Fariborz Jahanian894c57f2007-09-21 15:40:54 +0000816 if (ProtocolRefs.size() > 0)
817 return Actions.ObjcForwardProtocolDeclaration(CurScope, AtLoc,
818 &ProtocolRefs[0],
819 ProtocolRefs.size());
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000820 // Last, and definitely not least, parse a protocol declaration.
821 if (Tok.getKind() == tok::less) {
Steve Narofff28b2642007-09-05 23:30:30 +0000822 if (ParseObjCProtocolReferences(ProtocolRefs))
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000823 return 0;
824 }
Fariborz Jahanian25e077d2007-09-17 21:07:36 +0000825
Fariborz Jahanianccb4f312007-09-25 18:38:09 +0000826 DeclTy *ProtoType = Actions.ObjcStartProtoInterface(CurScope, AtLoc,
Fariborz Jahanian25e077d2007-09-17 21:07:36 +0000827 protocolName, nameLoc,
828 &ProtocolRefs[0],
829 ProtocolRefs.size());
830 ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol);
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000831
832 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
Steve Naroff861cf3e2007-08-23 18:16:40 +0000833 if (Tok.isObjCAtKeyword(tok::objc_end)) {
Steve Naroff7ef58fd2007-08-22 22:17:26 +0000834 ConsumeToken(); // the "end" identifier
835 return 0;
836 }
837 Diag(Tok, diag::err_objc_missing_end);
Steve Naroffdac269b2007-08-20 21:31:48 +0000838 return 0;
Reid Spencer5f016e22007-07-11 17:01:13 +0000839}
Steve Naroffdac269b2007-08-20 21:31:48 +0000840
841/// objc-implementation:
842/// objc-class-implementation-prologue
843/// objc-category-implementation-prologue
844///
845/// objc-class-implementation-prologue:
846/// @implementation identifier objc-superclass[opt]
847/// objc-class-instance-variables[opt]
848///
849/// objc-category-implementation-prologue:
850/// @implementation identifier ( identifier )
851
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +0000852Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration(
853 SourceLocation atLoc) {
854 assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
855 "ParseObjCAtImplementationDeclaration(): Expected @implementation");
856 ConsumeToken(); // the "implementation" identifier
857
858 if (Tok.getKind() != tok::identifier) {
859 Diag(Tok, diag::err_expected_ident); // missing class or category name.
860 return 0;
861 }
862 // We have a class or category name - consume it.
Fariborz Jahanianccb4f312007-09-25 18:38:09 +0000863 IdentifierInfo *nameId = Tok.getIdentifierInfo();
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +0000864 SourceLocation nameLoc = ConsumeToken(); // consume class or category name
865
866 if (Tok.getKind() == tok::l_paren) {
867 // we have a category implementation.
868 SourceLocation lparenLoc = ConsumeParen();
869 SourceLocation categoryLoc, rparenLoc;
870 IdentifierInfo *categoryId = 0;
871
872 if (Tok.getKind() == tok::identifier) {
873 categoryId = Tok.getIdentifierInfo();
874 categoryLoc = ConsumeToken();
875 } else {
876 Diag(Tok, diag::err_expected_ident); // missing category name.
877 return 0;
878 }
879 if (Tok.getKind() != tok::r_paren) {
880 Diag(Tok, diag::err_expected_rparen);
881 SkipUntil(tok::r_paren, false); // don't stop at ';'
882 return 0;
883 }
884 rparenLoc = ConsumeParen();
885 return 0;
886 }
887 // We have a class implementation
Fariborz Jahanianccb4f312007-09-25 18:38:09 +0000888 SourceLocation superClassLoc;
889 IdentifierInfo *superClassId = 0;
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +0000890 if (Tok.getKind() == tok::colon) {
891 // We have a super class
892 ConsumeToken();
893 if (Tok.getKind() != tok::identifier) {
894 Diag(Tok, diag::err_expected_ident); // missing super class name.
895 return 0;
896 }
Fariborz Jahanianccb4f312007-09-25 18:38:09 +0000897 superClassId = Tok.getIdentifierInfo();
898 superClassLoc = ConsumeToken(); // Consume super class name
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +0000899 }
Fariborz Jahanianccb4f312007-09-25 18:38:09 +0000900 DeclTy *ImplClsType = Actions.ObjcStartClassImplementation(CurScope,
901 atLoc,
902 nameId, nameLoc,
903 superClassId, superClassLoc);
904
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +0000905 if (Tok.getKind() == tok::l_brace)
Fariborz Jahanianccb4f312007-09-25 18:38:09 +0000906 ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/); // we have ivars
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +0000907
Fariborz Jahaniand0b01542007-09-27 18:57:03 +0000908 return ImplClsType;
Reid Spencer5f016e22007-07-11 17:01:13 +0000909}
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +0000910Parser::DeclTy *Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) {
911 assert(Tok.isObjCAtKeyword(tok::objc_end) &&
912 "ParseObjCAtEndDeclaration(): Expected @end");
913 ConsumeToken(); // the "end" identifier
Fariborz Jahaniand0b01542007-09-27 18:57:03 +0000914 if (ObjcImpDecl) {
915 // Checking is not necessary except that a parse error might have caused
916 // @implementation not to have been parsed to completion and ObjcImpDecl
917 // could be 0.
918 /// Insert collected methods declarations into the @interface object.
919 Actions.ObjcAddMethodsToClass(ObjcImpDecl,
920 &AllImplMethods[0],AllImplMethods.size());
921 ObjcImpDecl = 0;
922 AllImplMethods.clear();
923 }
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +0000924
Steve Naroffdac269b2007-08-20 21:31:48 +0000925 return 0;
926}
Fariborz Jahaniane992af02007-09-04 19:26:51 +0000927
928/// compatibility-alias-decl:
929/// @compatibility_alias alias-name class-name ';'
930///
931Parser::DeclTy *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
932 assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
933 "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
934 ConsumeToken(); // consume compatibility_alias
935 if (Tok.getKind() != tok::identifier) {
936 Diag(Tok, diag::err_expected_ident);
937 return 0;
938 }
939 ConsumeToken(); // consume alias-name
940 if (Tok.getKind() != tok::identifier) {
941 Diag(Tok, diag::err_expected_ident);
942 return 0;
943 }
944 ConsumeToken(); // consume class-name;
945 if (Tok.getKind() != tok::semi)
Fariborz Jahanian8cd8c662007-09-04 21:42:12 +0000946 Diag(Tok, diag::err_expected_semi_after, "@compatibility_alias");
Steve Naroffdac269b2007-08-20 21:31:48 +0000947 return 0;
Reid Spencer5f016e22007-07-11 17:01:13 +0000948}
949
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +0000950/// property-synthesis:
951/// @synthesize property-ivar-list ';'
952///
953/// property-ivar-list:
954/// property-ivar
955/// property-ivar-list ',' property-ivar
956///
957/// property-ivar:
958/// identifier
959/// identifier '=' identifier
960///
961Parser::DeclTy *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
962 assert(Tok.isObjCAtKeyword(tok::objc_synthesize) &&
963 "ParseObjCPropertyDynamic(): Expected '@synthesize'");
964 SourceLocation loc = ConsumeToken(); // consume dynamic
965 if (Tok.getKind() != tok::identifier) {
966 Diag(Tok, diag::err_expected_ident);
967 return 0;
968 }
969 while (Tok.getKind() == tok::identifier) {
970 ConsumeToken(); // consume property name
971 if (Tok.getKind() == tok::equal) {
972 // property '=' ivar-name
973 ConsumeToken(); // consume '='
974 if (Tok.getKind() != tok::identifier) {
975 Diag(Tok, diag::err_expected_ident);
976 break;
977 }
978 ConsumeToken(); // consume ivar-name
979 }
980 if (Tok.getKind() != tok::comma)
981 break;
982 ConsumeToken(); // consume ','
983 }
984 if (Tok.getKind() != tok::semi)
985 Diag(Tok, diag::err_expected_semi_after, "@synthesize");
986 return 0;
Reid Spencer5f016e22007-07-11 17:01:13 +0000987}
988
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +0000989/// property-dynamic:
990/// @dynamic property-list
991///
992/// property-list:
993/// identifier
994/// property-list ',' identifier
995///
996Parser::DeclTy *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
997 assert(Tok.isObjCAtKeyword(tok::objc_dynamic) &&
998 "ParseObjCPropertyDynamic(): Expected '@dynamic'");
999 SourceLocation loc = ConsumeToken(); // consume dynamic
1000 if (Tok.getKind() != tok::identifier) {
1001 Diag(Tok, diag::err_expected_ident);
1002 return 0;
1003 }
1004 while (Tok.getKind() == tok::identifier) {
1005 ConsumeToken(); // consume property name
1006 if (Tok.getKind() != tok::comma)
1007 break;
1008 ConsumeToken(); // consume ','
1009 }
1010 if (Tok.getKind() != tok::semi)
1011 Diag(Tok, diag::err_expected_semi_after, "@dynamic");
1012 return 0;
1013}
Fariborz Jahanian397fcc12007-09-19 19:14:32 +00001014
1015/// objc-throw-statement:
1016/// throw expression[opt];
1017///
1018Parser::DeclTy *Parser::ParseObjCThrowStmt(SourceLocation &atLoc) {
1019 ConsumeToken(); // consume throw
1020 if (Tok.getKind() != tok::semi) {
1021 ExprResult Res = ParseAssignmentExpression();
1022 if (Res.isInvalid) {
1023 SkipUntil(tok::semi);
1024 return 0;
1025 }
1026 }
1027 return 0;
1028}
1029
1030/// objc-try-catch-statement:
1031/// @try compound-statement objc-catch-list[opt]
1032/// @try compound-statement objc-catch-list[opt] @finally compound-statement
1033///
1034/// objc-catch-list:
1035/// @catch ( parameter-declaration ) compound-statement
1036/// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement
1037/// catch-parameter-declaration:
1038/// parameter-declaration
1039/// '...' [OBJC2]
1040///
1041Parser::DeclTy *Parser::ParseObjCTryStmt(SourceLocation &atLoc) {
1042 bool catch_or_finally_seen = false;
1043 ConsumeToken(); // consume try
1044 if (Tok.getKind() != tok::l_brace) {
1045 Diag (Tok, diag::err_expected_lbrace);
1046 return 0;
1047 }
1048 StmtResult TryBody = ParseCompoundStatementBody();
1049 while (Tok.getKind() == tok::at) {
1050 ConsumeToken();
1051 if (Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_catch) {
1052 SourceLocation catchLoc = ConsumeToken(); // consume catch
1053 if (Tok.getKind() == tok::l_paren) {
1054 ConsumeParen();
1055 if (Tok.getKind() != tok::ellipsis) {
1056 DeclSpec DS;
1057 ParseDeclarationSpecifiers(DS);
1058 // Parse the parameter-declaration.
1059 // FIXME: BlockContext may not be the right context!
1060 Declarator ParmDecl(DS, Declarator::BlockContext);
1061 ParseDeclarator(ParmDecl);
1062 }
1063 else
1064 ConsumeToken(); // consume '...'
1065 ConsumeParen();
1066 StmtResult CatchMody = ParseCompoundStatementBody();
1067 }
1068 else {
1069 Diag(catchLoc, diag::err_expected_lparen_after, "@catch clause");
1070 return 0;
1071 }
1072 catch_or_finally_seen = true;
1073 }
1074 else if (Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_finally) {
1075 ConsumeToken(); // consume finally
1076 StmtResult FinallyBody = ParseCompoundStatementBody();
1077 catch_or_finally_seen = true;
1078 break;
1079 }
1080 }
1081 if (!catch_or_finally_seen)
1082 Diag(atLoc, diag::err_missing_catch_finally);
1083 return 0;
1084}
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +00001085
Steve Naroff3536b442007-09-06 21:24:23 +00001086/// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +00001087///
1088void Parser::ParseObjCInstanceMethodDefinition() {
1089 assert(Tok.getKind() == tok::minus &&
1090 "ParseObjCInstanceMethodDefinition(): Expected '-'");
Fariborz Jahanian25e077d2007-09-17 21:07:36 +00001091 // FIXME: @optional/@protocol??
Fariborz Jahaniand0b01542007-09-27 18:57:03 +00001092 AllImplMethods.push_back(ParseObjCMethodPrototype(ObjcImpDecl));
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +00001093 // parse optional ';'
1094 if (Tok.getKind() == tok::semi)
1095 ConsumeToken();
1096
1097 if (Tok.getKind() != tok::l_brace) {
1098 Diag (Tok, diag::err_expected_lbrace);
1099 return;
1100 }
1101
1102 StmtResult FnBody = ParseCompoundStatementBody();
1103}
1104
Steve Naroff3536b442007-09-06 21:24:23 +00001105/// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +00001106///
Steve Naroff7ef58fd2007-08-22 22:17:26 +00001107void Parser::ParseObjCClassMethodDefinition() {
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +00001108 assert(Tok.getKind() == tok::plus &&
1109 "ParseObjCClassMethodDefinition(): Expected '+'");
Fariborz Jahanian25e077d2007-09-17 21:07:36 +00001110 // FIXME: @optional/@protocol??
Fariborz Jahaniand0b01542007-09-27 18:57:03 +00001111 AllImplMethods.push_back(ParseObjCMethodPrototype(ObjcImpDecl));
Fariborz Jahanianac00b7f2007-09-01 00:26:16 +00001112 // parse optional ';'
1113 if (Tok.getKind() == tok::semi)
1114 ConsumeToken();
1115 if (Tok.getKind() != tok::l_brace) {
1116 Diag (Tok, diag::err_expected_lbrace);
1117 return;
1118 }
1119
1120 StmtResult FnBody = ParseCompoundStatementBody();
Reid Spencer5f016e22007-07-11 17:01:13 +00001121}
Anders Carlsson55085182007-08-21 17:43:55 +00001122
Fariborz Jahanian397fcc12007-09-19 19:14:32 +00001123Parser::ExprResult Parser::ParseObjCExpression(SourceLocation &AtLoc) {
Anders Carlsson55085182007-08-21 17:43:55 +00001124
1125 switch (Tok.getKind()) {
1126 case tok::string_literal: // primary-expression: string-literal
1127 case tok::wide_string_literal:
1128 return ParseObjCStringLiteral();
Anders Carlsson29b2cb12007-08-23 15:25:28 +00001129 default:
1130 break;
1131 }
1132
1133 switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
Anders Carlssonf9bcf012007-08-22 15:14:15 +00001134 case tok::objc_encode:
1135 return ParseObjCEncodeExpression();
Anders Carlsson29b2cb12007-08-23 15:25:28 +00001136 case tok::objc_protocol:
1137 return ParseObjCProtocolExpression();
Anders Carlsson55085182007-08-21 17:43:55 +00001138 default:
1139 Diag(AtLoc, diag::err_unexpected_at);
1140 SkipUntil(tok::semi);
1141 break;
1142 }
1143
1144 return 0;
1145}
1146
Fariborz Jahanian0ccb27d2007-09-05 19:52:07 +00001147/// objc-message-expr:
1148/// '[' objc-receiver objc-message-args ']'
1149///
1150/// objc-receiver:
1151/// expression
1152/// class-name
1153/// type-name
1154///
1155/// objc-message-args:
1156/// objc-selector
1157/// objc-keywordarg-list
1158///
1159/// objc-keywordarg-list:
1160/// objc-keywordarg
1161/// objc-keywordarg-list objc-keywordarg
1162///
1163/// objc-keywordarg:
1164/// selector-name[opt] ':' objc-keywordexpr
1165///
1166/// objc-keywordexpr:
1167/// nonempty-expr-list
1168///
1169/// nonempty-expr-list:
1170/// assignment-expression
1171/// nonempty-expr-list , assignment-expression
1172///
1173Parser::ExprResult Parser::ParseObjCMessageExpression() {
Fariborz Jahaniana65ff6c2007-09-05 23:08:20 +00001174 assert(Tok.getKind() == tok::l_square && "'[' expected");
Steve Naroff563477d2007-09-18 23:55:05 +00001175 SourceLocation LBracloc = ConsumeBracket(); // consume '['
Steve Naroff37387c92007-09-17 20:25:27 +00001176 IdentifierInfo *ReceiverName = 0;
1177 ExprTy *ReceiverExpr = 0;
Fariborz Jahaniana65ff6c2007-09-05 23:08:20 +00001178 // Parse receiver
Steve Naroff8c9f13e2007-09-16 16:16:00 +00001179 if (Tok.getKind() == tok::identifier &&
Steve Naroff37387c92007-09-17 20:25:27 +00001180 Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) {
1181 ReceiverName = Tok.getIdentifierInfo();
Steve Naroff8c9f13e2007-09-16 16:16:00 +00001182 ConsumeToken();
Steve Naroff37387c92007-09-17 20:25:27 +00001183 } else {
1184 ExprResult Res = ParseAssignmentExpression();
1185 if (Res.isInvalid) {
1186 SkipUntil(tok::identifier);
1187 return Res;
1188 }
1189 ReceiverExpr = Res.Val;
1190 }
Fariborz Jahaniana65ff6c2007-09-05 23:08:20 +00001191 // Parse objc-selector
1192 IdentifierInfo *selIdent = ParseObjCSelector();
Steve Naroff68d331a2007-09-27 14:38:14 +00001193
1194 llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
1195 llvm::SmallVector<Action::ExprTy *, 12> KeyExprs;
1196
Fariborz Jahaniana65ff6c2007-09-05 23:08:20 +00001197 if (Tok.getKind() == tok::colon) {
1198 while (1) {
1199 // Each iteration parses a single keyword argument.
Steve Naroff68d331a2007-09-27 14:38:14 +00001200 KeyIdents.push_back(selIdent);
Steve Naroff37387c92007-09-17 20:25:27 +00001201
Fariborz Jahaniana65ff6c2007-09-05 23:08:20 +00001202 if (Tok.getKind() != tok::colon) {
1203 Diag(Tok, diag::err_expected_colon);
1204 SkipUntil(tok::semi);
Steve Naroff37387c92007-09-17 20:25:27 +00001205 return true;
Fariborz Jahaniana65ff6c2007-09-05 23:08:20 +00001206 }
Steve Naroff68d331a2007-09-27 14:38:14 +00001207 ConsumeToken(); // Eat the ':'.
Fariborz Jahaniana65ff6c2007-09-05 23:08:20 +00001208 /// Parse the expression after ':'
Steve Naroff37387c92007-09-17 20:25:27 +00001209 ExprResult Res = ParseAssignmentExpression();
1210 if (Res.isInvalid) {
1211 SkipUntil(tok::identifier);
1212 return Res;
1213 }
1214 // We have a valid expression.
Steve Naroff68d331a2007-09-27 14:38:14 +00001215 KeyExprs.push_back(Res.Val);
Steve Naroff37387c92007-09-17 20:25:27 +00001216
1217 // Check for another keyword selector.
1218 selIdent = ParseObjCSelector();
1219 if (!selIdent && Tok.getKind() != tok::colon)
Fariborz Jahaniana65ff6c2007-09-05 23:08:20 +00001220 break;
1221 // We have a selector or a colon, continue parsing.
1222 }
1223 // Parse the, optional, argument list, comma separated.
1224 while (Tok.getKind() == tok::comma) {
1225 ConsumeToken();
1226 /// Parse the expression after ','
1227 ParseAssignmentExpression();
1228 }
1229 } else if (!selIdent) {
1230 Diag(Tok, diag::err_expected_ident); // missing selector name.
1231 SkipUntil(tok::semi);
1232 return 0;
1233 }
1234 if (Tok.getKind() != tok::r_square) {
1235 Diag(Tok, diag::err_expected_rsquare);
1236 SkipUntil(tok::semi);
1237 return 0;
1238 }
Steve Naroff563477d2007-09-18 23:55:05 +00001239 SourceLocation RBracloc = ConsumeBracket(); // consume ']'
Steve Naroff37387c92007-09-17 20:25:27 +00001240
Steve Naroff68d331a2007-09-27 14:38:14 +00001241 if (KeyIdents.size()) {
Steve Naroffbcfb06a2007-09-28 22:22:11 +00001242 Selector sel = ObjcGetKeywordSelector(KeyIdents);
Steve Naroff708391a2007-09-17 21:01:15 +00001243 // We've just parsed a keyword message.
1244 if (ReceiverName)
Steve Naroffbcfb06a2007-09-28 22:22:11 +00001245 return Actions.ActOnClassMessage(ReceiverName, sel, LBracloc, RBracloc,
Steve Naroff68d331a2007-09-27 14:38:14 +00001246 &KeyExprs[0]);
Steve Naroffbcfb06a2007-09-28 22:22:11 +00001247 return Actions.ActOnInstanceMessage(ReceiverExpr, sel, LBracloc, RBracloc,
Steve Naroff68d331a2007-09-27 14:38:14 +00001248 &KeyExprs[0]);
Steve Naroff708391a2007-09-17 21:01:15 +00001249 }
Steve Naroffbcfb06a2007-09-28 22:22:11 +00001250 Selector sel = ObjcGetUnarySelector(selIdent);
Steve Naroff68d331a2007-09-27 14:38:14 +00001251
Steve Naroff708391a2007-09-17 21:01:15 +00001252 // We've just parsed a unary message (a message with no arguments).
Steve Naroff37387c92007-09-17 20:25:27 +00001253 if (ReceiverName)
Steve Naroffbcfb06a2007-09-28 22:22:11 +00001254 return Actions.ActOnClassMessage(ReceiverName, sel, LBracloc, RBracloc, 0);
1255 return Actions.ActOnInstanceMessage(ReceiverExpr, sel, LBracloc, RBracloc, 0);
Fariborz Jahanian0ccb27d2007-09-05 19:52:07 +00001256}
1257
Anders Carlsson55085182007-08-21 17:43:55 +00001258Parser::ExprResult Parser::ParseObjCStringLiteral() {
1259 ExprResult Res = ParseStringLiteralExpression();
1260
1261 if (Res.isInvalid) return Res;
1262
1263 return Actions.ParseObjCStringLiteral(Res.Val);
1264}
Anders Carlssonf9bcf012007-08-22 15:14:15 +00001265
1266/// objc-encode-expression:
1267/// @encode ( type-name )
1268Parser::ExprResult Parser::ParseObjCEncodeExpression() {
Steve Naroff861cf3e2007-08-23 18:16:40 +00001269 assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
Anders Carlssonf9bcf012007-08-22 15:14:15 +00001270
1271 SourceLocation EncLoc = ConsumeToken();
1272
1273 if (Tok.getKind() != tok::l_paren) {
1274 Diag(Tok, diag::err_expected_lparen_after, "@encode");
1275 return true;
1276 }
1277
1278 SourceLocation LParenLoc = ConsumeParen();
1279
1280 TypeTy *Ty = ParseTypeName();
1281
Anders Carlsson4988ae32007-08-23 15:31:37 +00001282 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
Anders Carlssonf9bcf012007-08-22 15:14:15 +00001283
1284 return Actions.ParseObjCEncodeExpression(EncLoc, LParenLoc, Ty,
Anders Carlsson4988ae32007-08-23 15:31:37 +00001285 RParenLoc);
Anders Carlssonf9bcf012007-08-22 15:14:15 +00001286}
Anders Carlsson29b2cb12007-08-23 15:25:28 +00001287
1288/// objc-protocol-expression
1289/// @protocol ( protocol-name )
1290
1291Parser::ExprResult Parser::ParseObjCProtocolExpression()
1292{
1293 SourceLocation ProtoLoc = ConsumeToken();
1294
1295 if (Tok.getKind() != tok::l_paren) {
1296 Diag(Tok, diag::err_expected_lparen_after, "@protocol");
1297 return true;
1298 }
1299
1300 SourceLocation LParenLoc = ConsumeParen();
1301
1302 if (Tok.getKind() != tok::identifier) {
1303 Diag(Tok, diag::err_expected_ident);
1304 return true;
1305 }
1306
1307 // FIXME: Do something with the protocol name
1308 ConsumeToken();
1309
Anders Carlsson4988ae32007-08-23 15:31:37 +00001310 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
Anders Carlsson29b2cb12007-08-23 15:25:28 +00001311
1312 // FIXME
1313 return 0;
1314}