blob: 83dba037fa94764ba269e8de1028687cd08ddac9 [file] [log] [blame]
Chris Lattner4b009652007-07-25 00:24:17 +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 Naroff09a0c4c2007-08-22 18:35:33 +000015#include "clang/Parse/DeclSpec.h"
Chris Lattner4b009652007-07-25 00:24:17 +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 Narofffb367882007-08-20 21:31:48 +000029Parser::DeclTy *Parser::ParseObjCAtDirectives() {
Chris Lattner4b009652007-07-25 00:24:17 +000030 SourceLocation AtLoc = ConsumeToken(); // the "@"
31
Steve Naroff87c329f2007-08-23 18:16:40 +000032 switch (Tok.getObjCKeywordID()) {
Chris Lattner4b009652007-07-25 00:24:17 +000033 case tok::objc_class:
34 return ParseObjCAtClassDeclaration(AtLoc);
35 case tok::objc_interface:
Steve Narofffb367882007-08-20 21:31:48 +000036 return ParseObjCAtInterfaceDeclaration(AtLoc);
Chris Lattner4b009652007-07-25 00:24:17 +000037 case tok::objc_protocol:
Steve Naroff72f17fb2007-08-22 22:17:26 +000038 return ParseObjCAtProtocolDeclaration(AtLoc);
Chris Lattner4b009652007-07-25 00:24:17 +000039 case tok::objc_implementation:
40 return ParseObjCAtImplementationDeclaration();
41 case tok::objc_end:
42 return ParseObjCAtEndDeclaration();
43 case tok::objc_compatibility_alias:
44 return ParseObjCAtAliasDeclaration();
45 default:
46 Diag(AtLoc, diag::err_unexpected_at);
47 SkipUntil(tok::semi);
Steve Narofffb367882007-08-20 21:31:48 +000048 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +000049 }
50}
51
52///
53/// objc-class-declaration:
54/// '@' 'class' identifier-list ';'
55///
Steve Narofffb367882007-08-20 21:31:48 +000056Parser::DeclTy *Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
Chris Lattner4b009652007-07-25 00:24:17 +000057 ConsumeToken(); // the identifier "class"
58 llvm::SmallVector<IdentifierInfo *, 8> ClassNames;
59
60 while (1) {
61 if (Tok.getKind() != tok::identifier) {
62 Diag(Tok, diag::err_expected_ident);
63 SkipUntil(tok::semi);
Steve Narofffb367882007-08-20 21:31:48 +000064 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +000065 }
Chris Lattner4b009652007-07-25 00:24:17 +000066 ClassNames.push_back(Tok.getIdentifierInfo());
67 ConsumeToken();
68
69 if (Tok.getKind() != tok::comma)
70 break;
71
72 ConsumeToken();
73 }
74
75 // Consume the ';'.
76 if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
Steve Narofffb367882007-08-20 21:31:48 +000077 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +000078
Steve Narofffb367882007-08-20 21:31:48 +000079 return Actions.ParsedObjcClassDeclaration(CurScope,
80 &ClassNames[0], ClassNames.size());
Chris Lattner4b009652007-07-25 00:24:17 +000081}
82
Steve Narofffb367882007-08-20 21:31:48 +000083///
84/// objc-interface:
85/// objc-class-interface-attributes[opt] objc-class-interface
86/// objc-category-interface
87///
88/// objc-class-interface:
89/// '@' 'interface' identifier objc-superclass[opt]
90/// objc-protocol-refs[opt]
91/// objc-class-instance-variables[opt]
92/// objc-interface-decl-list
93/// @end
94///
95/// objc-category-interface:
96/// '@' 'interface' identifier '(' identifier[opt] ')'
97/// objc-protocol-refs[opt]
98/// objc-interface-decl-list
99/// @end
100///
101/// objc-superclass:
102/// ':' identifier
103///
104/// objc-class-interface-attributes:
105/// __attribute__((visibility("default")))
106/// __attribute__((visibility("hidden")))
107/// __attribute__((deprecated))
108/// __attribute__((unavailable))
109/// __attribute__((objc_exception)) - used by NSException on 64-bit
110///
111Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration(
112 SourceLocation atLoc, AttributeList *attrList) {
Steve Naroff87c329f2007-08-23 18:16:40 +0000113 assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
Steve Narofffb367882007-08-20 21:31:48 +0000114 "ParseObjCAtInterfaceDeclaration(): Expected @interface");
115 ConsumeToken(); // the "interface" identifier
116
117 if (Tok.getKind() != tok::identifier) {
118 Diag(Tok, diag::err_expected_ident); // missing class or category name.
119 return 0;
120 }
121 // We have a class or category name - consume it.
Steve Naroff72f17fb2007-08-22 22:17:26 +0000122 IdentifierInfo *nameId = Tok.getIdentifierInfo();
Steve Narofffb367882007-08-20 21:31:48 +0000123 SourceLocation nameLoc = ConsumeToken();
124
Steve Naroffa7f62782007-08-23 19:56:30 +0000125 if (Tok.getKind() == tok::l_paren) { // we have a category.
Steve Narofffb367882007-08-20 21:31:48 +0000126 SourceLocation lparenLoc = ConsumeParen();
127 SourceLocation categoryLoc, rparenLoc;
128 IdentifierInfo *categoryId = 0;
129
Steve Naroffa7f62782007-08-23 19:56:30 +0000130 // For ObjC2, the category name is optional (not an error).
Steve Narofffb367882007-08-20 21:31:48 +0000131 if (Tok.getKind() == tok::identifier) {
132 categoryId = Tok.getIdentifierInfo();
133 categoryLoc = ConsumeToken();
Steve Naroffa7f62782007-08-23 19:56:30 +0000134 } else if (!getLang().ObjC2) {
135 Diag(Tok, diag::err_expected_ident); // missing category name.
136 return 0;
Steve Narofffb367882007-08-20 21:31:48 +0000137 }
138 if (Tok.getKind() != tok::r_paren) {
139 Diag(Tok, diag::err_expected_rparen);
140 SkipUntil(tok::r_paren, false); // don't stop at ';'
141 return 0;
142 }
143 rparenLoc = ConsumeParen();
144 // Next, we need to check for any protocol references.
145 if (Tok.getKind() == tok::less) {
146 if (ParseObjCProtocolReferences())
147 return 0;
148 }
149 if (attrList) // categories don't support attributes.
150 Diag(Tok, diag::err_objc_no_attributes_on_category);
151
Steve Naroff0bbffd82007-08-22 16:35:03 +0000152 ParseObjCInterfaceDeclList(0/*FIXME*/);
Steve Narofffb367882007-08-20 21:31:48 +0000153
Steve Naroff0bbffd82007-08-22 16:35:03 +0000154 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
Steve Naroff87c329f2007-08-23 18:16:40 +0000155 if (Tok.isObjCAtKeyword(tok::objc_end)) {
Steve Naroff0bbffd82007-08-22 16:35:03 +0000156 ConsumeToken(); // the "end" identifier
Steve Narofffb367882007-08-20 21:31:48 +0000157 return 0;
158 }
Steve Naroff0bbffd82007-08-22 16:35:03 +0000159 Diag(Tok, diag::err_objc_missing_end);
Steve Narofffb367882007-08-20 21:31:48 +0000160 return 0;
161 }
162 // Parse a class interface.
163 IdentifierInfo *superClassId = 0;
164 SourceLocation superClassLoc;
Steve Naroff72f17fb2007-08-22 22:17:26 +0000165
166 // FIXME: temporary hack to grok class names (until we have sema support).
167 llvm::SmallVector<IdentifierInfo *, 1> ClassName;
168 ClassName.push_back(nameId);
169 Actions.ParsedObjcClassDeclaration(CurScope, &ClassName[0], 1);
Steve Narofffb367882007-08-20 21:31:48 +0000170
171 if (Tok.getKind() == tok::colon) { // a super class is specified.
172 ConsumeToken();
173 if (Tok.getKind() != tok::identifier) {
174 Diag(Tok, diag::err_expected_ident); // missing super class name.
175 return 0;
176 }
177 superClassId = Tok.getIdentifierInfo();
178 superClassLoc = ConsumeToken();
179 }
180 // Next, we need to check for any protocol references.
181 if (Tok.getKind() == tok::less) {
182 if (ParseObjCProtocolReferences())
183 return 0;
184 }
Steve Naroffc4474992007-08-21 21:17:12 +0000185 // FIXME: add Actions.StartObjCClassInterface(nameId, superClassId, ...)
Steve Narofffb367882007-08-20 21:31:48 +0000186 if (Tok.getKind() == tok::l_brace)
Steve Naroffc4474992007-08-21 21:17:12 +0000187 ParseObjCClassInstanceVariables(0/*FIXME*/);
Steve Narofffb367882007-08-20 21:31:48 +0000188
Steve Naroff0bbffd82007-08-22 16:35:03 +0000189 ParseObjCInterfaceDeclList(0/*FIXME*/);
190
191 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
Steve Naroff87c329f2007-08-23 18:16:40 +0000192 if (Tok.isObjCAtKeyword(tok::objc_end)) {
Steve Naroff0bbffd82007-08-22 16:35:03 +0000193 ConsumeToken(); // the "end" identifier
Steve Narofffb367882007-08-20 21:31:48 +0000194 return 0;
195 }
Steve Naroff0bbffd82007-08-22 16:35:03 +0000196 Diag(Tok, diag::err_objc_missing_end);
Steve Narofffb367882007-08-20 21:31:48 +0000197 return 0;
198}
199
200/// objc-interface-decl-list:
201/// empty
Steve Narofffb367882007-08-20 21:31:48 +0000202/// objc-interface-decl-list objc-property-decl [OBJC2]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000203/// objc-interface-decl-list objc-method-requirement [OBJC2]
204/// objc-interface-decl-list objc-method-proto
Steve Narofffb367882007-08-20 21:31:48 +0000205/// objc-interface-decl-list declaration
206/// objc-interface-decl-list ';'
207///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000208/// objc-method-requirement: [OBJC2]
209/// @required
210/// @optional
211///
212void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl) {
213 while (1) {
214 if (Tok.getKind() == tok::at) {
215 SourceLocation AtLoc = ConsumeToken(); // the "@"
Steve Naroff87c329f2007-08-23 18:16:40 +0000216 tok::ObjCKeywordKind ocKind = Tok.getObjCKeywordID();
Steve Naroff0bbffd82007-08-22 16:35:03 +0000217
218 if (ocKind == tok::objc_end) { // terminate list
219 return;
220 } else if (ocKind == tok::objc_required) { // protocols only
221 ConsumeToken();
222 continue;
223 } else if (ocKind == tok::objc_optional) { // protocols only
224 ConsumeToken();
225 continue;
226 } else if (ocKind == tok::objc_property) {
Fariborz Jahanian6668b8c2007-08-31 16:11:31 +0000227 ParseObjCPropertyDecl(0/*FIXME*/);
Steve Naroff0bbffd82007-08-22 16:35:03 +0000228 continue;
229 } else {
230 Diag(Tok, diag::err_objc_illegal_interface_qual);
231 ConsumeToken();
232 }
233 }
234 if (Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) {
235 ParseObjCMethodPrototype();
236 continue;
237 }
238 if (Tok.getKind() == tok::semi)
239 ConsumeToken();
240 else if (Tok.getKind() == tok::eof)
241 return;
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000242 else
243 // FIXME: as the name implies, this rule allows function definitions.
244 // We could pass a flag or check for functions during semantic analysis.
Steve Naroff0bbffd82007-08-22 16:35:03 +0000245 ParseDeclarationOrFunctionDefinition();
246 }
247}
248
Fariborz Jahanian6668b8c2007-08-31 16:11:31 +0000249/// Parse property attribute declarations.
250///
251/// property-attr-decl: '(' property-attrlist ')'
252/// property-attrlist:
253/// property-attribute
254/// property-attrlist ',' property-attribute
255/// property-attribute:
256/// getter '=' identifier
257/// setter '=' identifier ':'
258/// readonly
259/// readwrite
260/// assign
261/// retain
262/// copy
263/// nonatomic
264///
265void Parser::ParseObjCPropertyAttribute (DeclTy *interfaceDecl) {
266 SourceLocation loc = ConsumeParen(); // consume '('
267 while (isObjCPropertyAttribute()) {
268 const IdentifierInfo *II = Tok.getIdentifierInfo();
269 // getter/setter require extra treatment.
270 if (II == ObjcPropertyAttrs[objc_getter] ||
271 II == ObjcPropertyAttrs[objc_setter]) {
272 // skip getter/setter part.
273 SourceLocation loc = ConsumeToken();
274 if (Tok.getKind() == tok::equal) {
275 loc = ConsumeToken();
276 if (Tok.getKind() == tok::identifier) {
277 if (II == ObjcPropertyAttrs[objc_setter]) {
278 loc = ConsumeToken(); // consume method name
279 if (Tok.getKind() != tok::colon) {
280 Diag(loc, diag::err_expected_colon);
281 SkipUntil(tok::r_paren,true,true);
282 break;
283 }
284 }
285 }
286 else {
287 Diag(loc, diag::err_expected_ident);
288 SkipUntil(tok::r_paren,true,true);
289 break;
290 }
291 }
292 else {
293 Diag(loc, diag::err_objc_expected_equal);
294 SkipUntil(tok::r_paren,true,true);
295 break;
296 }
297 }
298 ConsumeToken(); // consume last attribute token
299 if (Tok.getKind() == tok::comma) {
300 loc = ConsumeToken();
301 continue;
302 }
303 if (Tok.getKind() == tok::r_paren)
304 break;
305 Diag(loc, diag::err_expected_rparen);
306 SkipUntil(tok::semi);
307 return;
308 }
309 if (Tok.getKind() == tok::r_paren)
310 ConsumeParen();
311 else {
312 Diag(loc, diag::err_objc_expected_property_attr);
313 SkipUntil(tok::r_paren); // recover from error inside attribute list
314 }
315}
316
317/// Main routine to parse property declaration.
318///
319/// @property property-attr-decl[opt] property-component-decl ';'
320///
321void Parser::ParseObjCPropertyDecl(DeclTy *interfaceDecl) {
322 assert(Tok.isObjCAtKeyword(tok::objc_property) &&
323 "ParseObjCPropertyDecl(): Expected @property");
324 ConsumeToken(); // the "property" identifier
325 // Parse property attribute list, if any.
326 if (Tok.getKind() == tok::l_paren) {
327 // property has attribute list.
328 ParseObjCPropertyAttribute(0/*FIXME*/);
329 }
330 // Parse declaration portion of @property.
331 llvm::SmallVector<DeclTy*, 32> PropertyDecls;
332 ParseStructDeclaration(interfaceDecl, PropertyDecls);
333 if (Tok.getKind() == tok::semi)
334 ConsumeToken();
335 else {
336 Diag(Tok, diag::err_expected_semi_decl_list);
337 SkipUntil(tok::r_brace, true, true);
338 }
Chris Lattner4b009652007-07-25 00:24:17 +0000339}
Steve Narofffb367882007-08-20 21:31:48 +0000340
Steve Naroff0bbffd82007-08-22 16:35:03 +0000341/// objc-methodproto:
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000342/// objc-instance-method objc-method-decl objc-method-attributes[opt] ';'
343/// objc-class-method objc-method-decl objc-method-attributes[opt] ';'
Steve Naroff0bbffd82007-08-22 16:35:03 +0000344///
345/// objc-instance-method: '-'
346/// objc-class-method: '+'
347///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000348/// objc-method-attributes: [OBJC2]
349/// __attribute__((deprecated))
350///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000351void Parser::ParseObjCMethodPrototype() {
352 assert((Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) &&
353 "expected +/-");
354
355 tok::TokenKind methodType = Tok.getKind();
356 SourceLocation methodLoc = ConsumeToken();
357
358 // FIXME: deal with "context sensitive" protocol qualifiers in prototypes
359 ParseObjCMethodDecl(methodType, methodLoc);
360
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000361 // If attributes exist after the method, parse them.
Steve Naroffa7f62782007-08-23 19:56:30 +0000362 if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000363 ParseAttributes();
364
Steve Naroff0bbffd82007-08-22 16:35:03 +0000365 // Consume the ';'.
366 ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "method proto");
367}
368
369/// objc-selector:
370/// identifier
371/// one of
372/// enum struct union if else while do for switch case default
373/// break continue return goto asm sizeof typeof __alignof
374/// unsigned long const short volatile signed restrict _Complex
375/// in out inout bycopy byref oneway int char float double void _Bool
376///
377IdentifierInfo *Parser::ParseObjCSelector() {
378 tok::TokenKind tKind = Tok.getKind();
379 IdentifierInfo *II = 0;
380
381 if (tKind == tok::identifier ||
382 (tKind >= tok::kw_auto && tKind <= tok::kw__Complex)) {
383 // FIXME: make sure the list of keywords jives with gcc. For example,
384 // the above test does not include in/out/inout/bycopy/byref/oneway.
385 II = Tok.getIdentifierInfo();
386 ConsumeToken();
387 }
388 return II;
389}
390
Steve Naroffa8ee2262007-08-22 23:18:22 +0000391/// objc-type-qualifier: one of
392/// in out inout bycopy byref oneway
393///
Steve Naroffa8ee2262007-08-22 23:18:22 +0000394bool Parser::isObjCTypeQualifier() {
395 if (Tok.getKind() == tok::identifier) {
Chris Lattner32352462007-08-29 22:54:08 +0000396 const IdentifierInfo *II = Tok.getIdentifierInfo();
397 for (unsigned i = 0; i < objc_NumQuals; ++i)
398 if (II == ObjcTypeQuals[i]) return true;
Steve Naroffa8ee2262007-08-22 23:18:22 +0000399 }
400 return false;
401}
402
Fariborz Jahanian6668b8c2007-08-31 16:11:31 +0000403/// property-attrlist: one of
404/// readonly getter setter assign retain copy nonatomic
405///
406bool Parser::isObjCPropertyAttribute() {
407 if (Tok.getKind() == tok::identifier) {
408 const IdentifierInfo *II = Tok.getIdentifierInfo();
409 for (unsigned i = 0; i < objc_NumAttrs; ++i)
410 if (II == ObjcPropertyAttrs[i]) return true;
411 }
412 return false;
413}
414
Steve Naroff0bbffd82007-08-22 16:35:03 +0000415/// objc-type-name:
416/// '(' objc-type-qualifiers[opt] type-name ')'
417/// '(' objc-type-qualifiers[opt] ')'
418///
419/// objc-type-qualifiers:
420/// objc-type-qualifier
421/// objc-type-qualifiers objc-type-qualifier
422///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000423void Parser::ParseObjCTypeName() {
424 assert(Tok.getKind() == tok::l_paren && "expected (");
425
426 SourceLocation LParenLoc = ConsumeParen(), RParenLoc;
427
Steve Naroffa8ee2262007-08-22 23:18:22 +0000428 while (isObjCTypeQualifier())
429 ConsumeToken();
430
Steve Naroff0bbffd82007-08-22 16:35:03 +0000431 if (isTypeSpecifierQualifier()) {
Steve Naroff72f17fb2007-08-22 22:17:26 +0000432 //TypeTy *Ty = ParseTypeName();
433 //assert(Ty && "Parser::ParseObjCTypeName(): missing type");
434 ParseTypeName(); // FIXME: when sema support is added.
Steve Naroff0bbffd82007-08-22 16:35:03 +0000435 }
436 if (Tok.getKind() != tok::r_paren) {
437 MatchRHSPunctuation(tok::r_paren, LParenLoc);
438 return;
439 }
440 RParenLoc = ConsumeParen();
441}
442
443/// objc-method-decl:
444/// objc-selector
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000445/// objc-keyword-selector objc-parmlist[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000446/// objc-type-name objc-selector
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000447/// objc-type-name objc-keyword-selector objc-parmlist[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000448///
449/// objc-keyword-selector:
Steve Naroff72f17fb2007-08-22 22:17:26 +0000450/// objc-keyword-decl
Steve Naroff0bbffd82007-08-22 16:35:03 +0000451/// objc-keyword-selector objc-keyword-decl
452///
453/// objc-keyword-decl:
Steve Naroff72f17fb2007-08-22 22:17:26 +0000454/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
455/// objc-selector ':' objc-keyword-attributes[opt] identifier
456/// ':' objc-type-name objc-keyword-attributes[opt] identifier
457/// ':' objc-keyword-attributes[opt] identifier
Steve Naroff0bbffd82007-08-22 16:35:03 +0000458///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000459/// objc-parmlist:
460/// objc-parms objc-ellipsis[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000461///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000462/// objc-parms:
463/// objc-parms , parameter-declaration
Steve Naroff0bbffd82007-08-22 16:35:03 +0000464///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000465/// objc-ellipsis:
Steve Naroff0bbffd82007-08-22 16:35:03 +0000466/// , ...
467///
Steve Naroff72f17fb2007-08-22 22:17:26 +0000468/// objc-keyword-attributes: [OBJC2]
469/// __attribute__((unused))
470///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000471void Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc) {
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000472
473 // Parse the return type.
Steve Naroff0bbffd82007-08-22 16:35:03 +0000474 if (Tok.getKind() == tok::l_paren)
475 ParseObjCTypeName();
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000476 IdentifierInfo *selIdent = ParseObjCSelector();
477
478 if (Tok.getKind() == tok::colon) {
479 IdentifierInfo *keywordSelector = selIdent;
480 while (1) {
481 // Each iteration parses a single keyword argument.
482 if (Tok.getKind() != tok::colon) {
483 Diag(Tok, diag::err_expected_colon);
484 break;
485 }
486 ConsumeToken(); // Eat the ':'.
487 if (Tok.getKind() == tok::l_paren) // Parse the argument type.
488 ParseObjCTypeName();
Steve Naroff72f17fb2007-08-22 22:17:26 +0000489
490 // If attributes exist before the argument name, parse them.
Steve Naroffa7f62782007-08-23 19:56:30 +0000491 if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
Steve Naroff72f17fb2007-08-22 22:17:26 +0000492 ParseAttributes();
493
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000494 if (Tok.getKind() != tok::identifier) {
495 Diag(Tok, diag::err_expected_ident); // missing argument name.
496 break;
497 }
498 ConsumeToken(); // Eat the identifier.
499 // FIXME: add Actions.BuildObjCKeyword()
500
501 keywordSelector = ParseObjCSelector();
502 if (!keywordSelector && Tok.getKind() != tok::colon)
503 break;
504 // We have a selector or a colon, continue parsing.
505 }
506 // Parse the (optional) parameter list.
507 while (Tok.getKind() == tok::comma) {
508 ConsumeToken();
509 if (Tok.getKind() == tok::ellipsis) {
510 ConsumeToken();
511 break;
512 }
513 ParseDeclaration(Declarator::PrototypeContext);
514 }
515 } else if (!selIdent) {
516 Diag(Tok, diag::err_expected_ident); // missing selector name.
517 }
518 // FIXME: add Actions.BuildMethodSignature().
Steve Naroff0bbffd82007-08-22 16:35:03 +0000519}
520
Steve Narofffb367882007-08-20 21:31:48 +0000521/// objc-protocol-refs:
522/// '<' identifier-list '>'
523///
524bool Parser::ParseObjCProtocolReferences() {
525 assert(Tok.getKind() == tok::less && "expected <");
526
527 ConsumeToken(); // the "<"
528 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
529
530 while (1) {
531 if (Tok.getKind() != tok::identifier) {
532 Diag(Tok, diag::err_expected_ident);
533 SkipUntil(tok::greater);
534 return true;
535 }
536 ProtocolRefs.push_back(Tok.getIdentifierInfo());
537 ConsumeToken();
538
539 if (Tok.getKind() != tok::comma)
540 break;
541 ConsumeToken();
542 }
543 // Consume the '>'.
544 return ExpectAndConsume(tok::greater, diag::err_expected_greater);
545}
546
547/// objc-class-instance-variables:
548/// '{' objc-instance-variable-decl-list[opt] '}'
549///
550/// objc-instance-variable-decl-list:
551/// objc-visibility-spec
552/// objc-instance-variable-decl ';'
553/// ';'
554/// objc-instance-variable-decl-list objc-visibility-spec
555/// objc-instance-variable-decl-list objc-instance-variable-decl ';'
556/// objc-instance-variable-decl-list ';'
557///
558/// objc-visibility-spec:
559/// @private
560/// @protected
561/// @public
Steve Naroffc4474992007-08-21 21:17:12 +0000562/// @package [OBJC2]
Steve Narofffb367882007-08-20 21:31:48 +0000563///
564/// objc-instance-variable-decl:
565/// struct-declaration
566///
Steve Naroffc4474992007-08-21 21:17:12 +0000567void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl) {
568 assert(Tok.getKind() == tok::l_brace && "expected {");
569
570 SourceLocation LBraceLoc = ConsumeBrace(); // the "{"
571 llvm::SmallVector<DeclTy*, 32> IvarDecls;
572
573 // While we still have something to read, read the instance variables.
574 while (Tok.getKind() != tok::r_brace &&
575 Tok.getKind() != tok::eof) {
576 // Each iteration of this loop reads one objc-instance-variable-decl.
577
578 // Check for extraneous top-level semicolon.
579 if (Tok.getKind() == tok::semi) {
580 Diag(Tok, diag::ext_extra_struct_semi);
581 ConsumeToken();
582 continue;
583 }
584 // Set the default visibility to private.
585 tok::ObjCKeywordKind visibility = tok::objc_private;
586 if (Tok.getKind() == tok::at) { // parse objc-visibility-spec
587 ConsumeToken(); // eat the @ sign
Steve Naroff87c329f2007-08-23 18:16:40 +0000588 switch (Tok.getObjCKeywordID()) {
Steve Naroffc4474992007-08-21 21:17:12 +0000589 case tok::objc_private:
590 case tok::objc_public:
591 case tok::objc_protected:
592 case tok::objc_package:
Steve Naroff87c329f2007-08-23 18:16:40 +0000593 visibility = Tok.getObjCKeywordID();
Steve Naroffc4474992007-08-21 21:17:12 +0000594 ConsumeToken();
595 continue;
596 default:
597 Diag(Tok, diag::err_objc_illegal_visibility_spec);
598 ConsumeToken();
599 continue;
600 }
601 }
602 ParseStructDeclaration(interfaceDecl, IvarDecls);
603
604 if (Tok.getKind() == tok::semi) {
605 ConsumeToken();
606 } else if (Tok.getKind() == tok::r_brace) {
607 Diag(Tok.getLocation(), diag::ext_expected_semi_decl_list);
608 break;
609 } else {
610 Diag(Tok, diag::err_expected_semi_decl_list);
611 // Skip to end of block or statement
612 SkipUntil(tok::r_brace, true, true);
613 }
614 }
615 MatchRHSPunctuation(tok::r_brace, LBraceLoc);
616 return;
Chris Lattner4b009652007-07-25 00:24:17 +0000617}
Steve Narofffb367882007-08-20 21:31:48 +0000618
619/// objc-protocol-declaration:
620/// objc-protocol-definition
621/// objc-protocol-forward-reference
622///
623/// objc-protocol-definition:
624/// @protocol identifier
625/// objc-protocol-refs[opt]
626/// objc-methodprotolist
627/// @end
628///
629/// objc-protocol-forward-reference:
630/// @protocol identifier-list ';'
631///
632/// "@protocol identifier ;" should be resolved as "@protocol
633/// identifier-list ;": objc-methodprotolist may not start with a
634/// semicolon in the first alternative if objc-protocol-refs are omitted.
635
Steve Naroff72f17fb2007-08-22 22:17:26 +0000636Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) {
Steve Naroff87c329f2007-08-23 18:16:40 +0000637 assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
Steve Naroff72f17fb2007-08-22 22:17:26 +0000638 "ParseObjCAtProtocolDeclaration(): Expected @protocol");
639 ConsumeToken(); // the "protocol" identifier
640
641 if (Tok.getKind() != tok::identifier) {
642 Diag(Tok, diag::err_expected_ident); // missing protocol name.
643 return 0;
644 }
645 // Save the protocol name, then consume it.
646 IdentifierInfo *protocolName = Tok.getIdentifierInfo();
647 SourceLocation nameLoc = ConsumeToken();
648
649 if (Tok.getKind() == tok::semi) { // forward declaration.
650 ConsumeToken();
651 return 0; // FIXME: add protocolName
652 }
653 if (Tok.getKind() == tok::comma) { // list of forward declarations.
654 // Parse the list of forward declarations.
655 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
656 ProtocolRefs.push_back(protocolName);
657
658 while (1) {
659 ConsumeToken(); // the ','
660 if (Tok.getKind() != tok::identifier) {
661 Diag(Tok, diag::err_expected_ident);
662 SkipUntil(tok::semi);
663 return 0;
664 }
665 ProtocolRefs.push_back(Tok.getIdentifierInfo());
666 ConsumeToken(); // the identifier
667
668 if (Tok.getKind() != tok::comma)
669 break;
670 }
671 // Consume the ';'.
672 if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
673 return 0;
674 return 0; // FIXME
675 }
676 // Last, and definitely not least, parse a protocol declaration.
677 if (Tok.getKind() == tok::less) {
678 if (ParseObjCProtocolReferences())
679 return 0;
680 }
681 ParseObjCInterfaceDeclList(0/*FIXME*/);
682
683 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
Steve Naroff87c329f2007-08-23 18:16:40 +0000684 if (Tok.isObjCAtKeyword(tok::objc_end)) {
Steve Naroff72f17fb2007-08-22 22:17:26 +0000685 ConsumeToken(); // the "end" identifier
686 return 0;
687 }
688 Diag(Tok, diag::err_objc_missing_end);
Steve Narofffb367882007-08-20 21:31:48 +0000689 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000690}
Steve Narofffb367882007-08-20 21:31:48 +0000691
692/// objc-implementation:
693/// objc-class-implementation-prologue
694/// objc-category-implementation-prologue
695///
696/// objc-class-implementation-prologue:
697/// @implementation identifier objc-superclass[opt]
698/// objc-class-instance-variables[opt]
699///
700/// objc-category-implementation-prologue:
701/// @implementation identifier ( identifier )
702
703Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000704 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000705 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000706}
Steve Narofffb367882007-08-20 21:31:48 +0000707Parser::DeclTy *Parser::ParseObjCAtEndDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000708 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000709 return 0;
710}
711Parser::DeclTy *Parser::ParseObjCAtAliasDeclaration() {
712 assert(0 && "Unimp");
713 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000714}
715
Steve Naroff72f17fb2007-08-22 22:17:26 +0000716void Parser::ParseObjCInstanceMethodDefinition() {
717 assert(0 && "Parser::ParseObjCInstanceMethodDefinition():: Unimp");
Chris Lattner4b009652007-07-25 00:24:17 +0000718}
719
Steve Naroff72f17fb2007-08-22 22:17:26 +0000720void Parser::ParseObjCClassMethodDefinition() {
721 assert(0 && "Parser::ParseObjCClassMethodDefinition():: Unimp");
Chris Lattner4b009652007-07-25 00:24:17 +0000722}
Anders Carlssona66cad42007-08-21 17:43:55 +0000723
724Parser::ExprResult Parser::ParseObjCExpression() {
725 SourceLocation AtLoc = ConsumeToken(); // the "@"
726
727 switch (Tok.getKind()) {
728 case tok::string_literal: // primary-expression: string-literal
729 case tok::wide_string_literal:
730 return ParseObjCStringLiteral();
Anders Carlsson2996b4e2007-08-23 15:25:28 +0000731 default:
732 break;
733 }
734
735 switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
Anders Carlsson8be1d402007-08-22 15:14:15 +0000736 case tok::objc_encode:
737 return ParseObjCEncodeExpression();
Anders Carlsson2996b4e2007-08-23 15:25:28 +0000738 case tok::objc_protocol:
739 return ParseObjCProtocolExpression();
Anders Carlssona66cad42007-08-21 17:43:55 +0000740 default:
741 Diag(AtLoc, diag::err_unexpected_at);
742 SkipUntil(tok::semi);
743 break;
744 }
745
746 return 0;
747}
748
749Parser::ExprResult Parser::ParseObjCStringLiteral() {
750 ExprResult Res = ParseStringLiteralExpression();
751
752 if (Res.isInvalid) return Res;
753
754 return Actions.ParseObjCStringLiteral(Res.Val);
755}
Anders Carlsson8be1d402007-08-22 15:14:15 +0000756
757/// objc-encode-expression:
758/// @encode ( type-name )
759Parser::ExprResult Parser::ParseObjCEncodeExpression() {
Steve Naroff87c329f2007-08-23 18:16:40 +0000760 assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
Anders Carlsson8be1d402007-08-22 15:14:15 +0000761
762 SourceLocation EncLoc = ConsumeToken();
763
764 if (Tok.getKind() != tok::l_paren) {
765 Diag(Tok, diag::err_expected_lparen_after, "@encode");
766 return true;
767 }
768
769 SourceLocation LParenLoc = ConsumeParen();
770
771 TypeTy *Ty = ParseTypeName();
772
Anders Carlsson92faeb82007-08-23 15:31:37 +0000773 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
Anders Carlsson8be1d402007-08-22 15:14:15 +0000774
775 return Actions.ParseObjCEncodeExpression(EncLoc, LParenLoc, Ty,
Anders Carlsson92faeb82007-08-23 15:31:37 +0000776 RParenLoc);
Anders Carlsson8be1d402007-08-22 15:14:15 +0000777}
Anders Carlsson2996b4e2007-08-23 15:25:28 +0000778
779/// objc-protocol-expression
780/// @protocol ( protocol-name )
781
782Parser::ExprResult Parser::ParseObjCProtocolExpression()
783{
784 SourceLocation ProtoLoc = ConsumeToken();
785
786 if (Tok.getKind() != tok::l_paren) {
787 Diag(Tok, diag::err_expected_lparen_after, "@protocol");
788 return true;
789 }
790
791 SourceLocation LParenLoc = ConsumeParen();
792
793 if (Tok.getKind() != tok::identifier) {
794 Diag(Tok, diag::err_expected_ident);
795 return true;
796 }
797
798 // FIXME: Do something with the protocol name
799 ConsumeToken();
800
Anders Carlsson92faeb82007-08-23 15:31:37 +0000801 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
Anders Carlsson2996b4e2007-08-23 15:25:28 +0000802
803 // FIXME
804 return 0;
805}