blob: 4b3c60079466086c35aaee361e5b9c63bf74369f [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) {
227 ParseObjCPropertyDecl(AtLoc);
228 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
249void Parser::ParseObjCPropertyDecl(SourceLocation atLoc) {
Chris Lattner4b009652007-07-25 00:24:17 +0000250 assert(0 && "Unimp");
251}
Steve Narofffb367882007-08-20 21:31:48 +0000252
Steve Naroff0bbffd82007-08-22 16:35:03 +0000253/// objc-methodproto:
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000254/// objc-instance-method objc-method-decl objc-method-attributes[opt] ';'
255/// objc-class-method objc-method-decl objc-method-attributes[opt] ';'
Steve Naroff0bbffd82007-08-22 16:35:03 +0000256///
257/// objc-instance-method: '-'
258/// objc-class-method: '+'
259///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000260/// objc-method-attributes: [OBJC2]
261/// __attribute__((deprecated))
262///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000263void Parser::ParseObjCMethodPrototype() {
264 assert((Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) &&
265 "expected +/-");
266
267 tok::TokenKind methodType = Tok.getKind();
268 SourceLocation methodLoc = ConsumeToken();
269
270 // FIXME: deal with "context sensitive" protocol qualifiers in prototypes
271 ParseObjCMethodDecl(methodType, methodLoc);
272
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000273 // If attributes exist after the method, parse them.
Steve Naroffa7f62782007-08-23 19:56:30 +0000274 if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000275 ParseAttributes();
276
Steve Naroff0bbffd82007-08-22 16:35:03 +0000277 // Consume the ';'.
278 ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "method proto");
279}
280
281/// objc-selector:
282/// identifier
283/// one of
284/// enum struct union if else while do for switch case default
285/// break continue return goto asm sizeof typeof __alignof
286/// unsigned long const short volatile signed restrict _Complex
287/// in out inout bycopy byref oneway int char float double void _Bool
288///
289IdentifierInfo *Parser::ParseObjCSelector() {
290 tok::TokenKind tKind = Tok.getKind();
291 IdentifierInfo *II = 0;
292
293 if (tKind == tok::identifier ||
294 (tKind >= tok::kw_auto && tKind <= tok::kw__Complex)) {
295 // FIXME: make sure the list of keywords jives with gcc. For example,
296 // the above test does not include in/out/inout/bycopy/byref/oneway.
297 II = Tok.getIdentifierInfo();
298 ConsumeToken();
299 }
300 return II;
301}
302
Steve Naroffa8ee2262007-08-22 23:18:22 +0000303/// objc-type-qualifier: one of
304/// in out inout bycopy byref oneway
305///
306/// FIXME: remove the string compares...
307bool Parser::isObjCTypeQualifier() {
308 if (Tok.getKind() == tok::identifier) {
309 const char *qual = Tok.getIdentifierInfo()->getName();
310 return (strcmp(qual, "in") == 0) || (strcmp(qual, "out") == 0) ||
311 (strcmp(qual, "inout") == 0) || (strcmp(qual, "oneway") == 0) ||
312 (strcmp(qual, "bycopy") == 0) || (strcmp(qual, "byref") == 0);
313 }
314 return false;
315}
316
Steve Naroff0bbffd82007-08-22 16:35:03 +0000317/// objc-type-name:
318/// '(' objc-type-qualifiers[opt] type-name ')'
319/// '(' objc-type-qualifiers[opt] ')'
320///
321/// objc-type-qualifiers:
322/// objc-type-qualifier
323/// objc-type-qualifiers objc-type-qualifier
324///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000325void Parser::ParseObjCTypeName() {
326 assert(Tok.getKind() == tok::l_paren && "expected (");
327
328 SourceLocation LParenLoc = ConsumeParen(), RParenLoc;
329
Steve Naroffa8ee2262007-08-22 23:18:22 +0000330 while (isObjCTypeQualifier())
331 ConsumeToken();
332
Steve Naroff0bbffd82007-08-22 16:35:03 +0000333 if (isTypeSpecifierQualifier()) {
Steve Naroff72f17fb2007-08-22 22:17:26 +0000334 //TypeTy *Ty = ParseTypeName();
335 //assert(Ty && "Parser::ParseObjCTypeName(): missing type");
336 ParseTypeName(); // FIXME: when sema support is added.
Steve Naroff0bbffd82007-08-22 16:35:03 +0000337 }
338 if (Tok.getKind() != tok::r_paren) {
339 MatchRHSPunctuation(tok::r_paren, LParenLoc);
340 return;
341 }
342 RParenLoc = ConsumeParen();
343}
344
345/// objc-method-decl:
346/// objc-selector
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000347/// objc-keyword-selector objc-parmlist[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000348/// objc-type-name objc-selector
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000349/// objc-type-name objc-keyword-selector objc-parmlist[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000350///
351/// objc-keyword-selector:
Steve Naroff72f17fb2007-08-22 22:17:26 +0000352/// objc-keyword-decl
Steve Naroff0bbffd82007-08-22 16:35:03 +0000353/// objc-keyword-selector objc-keyword-decl
354///
355/// objc-keyword-decl:
Steve Naroff72f17fb2007-08-22 22:17:26 +0000356/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
357/// objc-selector ':' objc-keyword-attributes[opt] identifier
358/// ':' objc-type-name objc-keyword-attributes[opt] identifier
359/// ':' objc-keyword-attributes[opt] identifier
Steve Naroff0bbffd82007-08-22 16:35:03 +0000360///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000361/// objc-parmlist:
362/// objc-parms objc-ellipsis[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000363///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000364/// objc-parms:
365/// objc-parms , parameter-declaration
Steve Naroff0bbffd82007-08-22 16:35:03 +0000366///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000367/// objc-ellipsis:
Steve Naroff0bbffd82007-08-22 16:35:03 +0000368/// , ...
369///
Steve Naroff72f17fb2007-08-22 22:17:26 +0000370/// objc-keyword-attributes: [OBJC2]
371/// __attribute__((unused))
372///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000373void Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc) {
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000374
375 // Parse the return type.
Steve Naroff0bbffd82007-08-22 16:35:03 +0000376 if (Tok.getKind() == tok::l_paren)
377 ParseObjCTypeName();
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000378 IdentifierInfo *selIdent = ParseObjCSelector();
379
380 if (Tok.getKind() == tok::colon) {
381 IdentifierInfo *keywordSelector = selIdent;
382 while (1) {
383 // Each iteration parses a single keyword argument.
384 if (Tok.getKind() != tok::colon) {
385 Diag(Tok, diag::err_expected_colon);
386 break;
387 }
388 ConsumeToken(); // Eat the ':'.
389 if (Tok.getKind() == tok::l_paren) // Parse the argument type.
390 ParseObjCTypeName();
Steve Naroff72f17fb2007-08-22 22:17:26 +0000391
392 // If attributes exist before the argument name, parse them.
Steve Naroffa7f62782007-08-23 19:56:30 +0000393 if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
Steve Naroff72f17fb2007-08-22 22:17:26 +0000394 ParseAttributes();
395
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000396 if (Tok.getKind() != tok::identifier) {
397 Diag(Tok, diag::err_expected_ident); // missing argument name.
398 break;
399 }
400 ConsumeToken(); // Eat the identifier.
401 // FIXME: add Actions.BuildObjCKeyword()
402
403 keywordSelector = ParseObjCSelector();
404 if (!keywordSelector && Tok.getKind() != tok::colon)
405 break;
406 // We have a selector or a colon, continue parsing.
407 }
408 // Parse the (optional) parameter list.
409 while (Tok.getKind() == tok::comma) {
410 ConsumeToken();
411 if (Tok.getKind() == tok::ellipsis) {
412 ConsumeToken();
413 break;
414 }
415 ParseDeclaration(Declarator::PrototypeContext);
416 }
417 } else if (!selIdent) {
418 Diag(Tok, diag::err_expected_ident); // missing selector name.
419 }
420 // FIXME: add Actions.BuildMethodSignature().
Steve Naroff0bbffd82007-08-22 16:35:03 +0000421}
422
Steve Narofffb367882007-08-20 21:31:48 +0000423/// objc-protocol-refs:
424/// '<' identifier-list '>'
425///
426bool Parser::ParseObjCProtocolReferences() {
427 assert(Tok.getKind() == tok::less && "expected <");
428
429 ConsumeToken(); // the "<"
430 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
431
432 while (1) {
433 if (Tok.getKind() != tok::identifier) {
434 Diag(Tok, diag::err_expected_ident);
435 SkipUntil(tok::greater);
436 return true;
437 }
438 ProtocolRefs.push_back(Tok.getIdentifierInfo());
439 ConsumeToken();
440
441 if (Tok.getKind() != tok::comma)
442 break;
443 ConsumeToken();
444 }
445 // Consume the '>'.
446 return ExpectAndConsume(tok::greater, diag::err_expected_greater);
447}
448
449/// objc-class-instance-variables:
450/// '{' objc-instance-variable-decl-list[opt] '}'
451///
452/// objc-instance-variable-decl-list:
453/// objc-visibility-spec
454/// objc-instance-variable-decl ';'
455/// ';'
456/// objc-instance-variable-decl-list objc-visibility-spec
457/// objc-instance-variable-decl-list objc-instance-variable-decl ';'
458/// objc-instance-variable-decl-list ';'
459///
460/// objc-visibility-spec:
461/// @private
462/// @protected
463/// @public
Steve Naroffc4474992007-08-21 21:17:12 +0000464/// @package [OBJC2]
Steve Narofffb367882007-08-20 21:31:48 +0000465///
466/// objc-instance-variable-decl:
467/// struct-declaration
468///
Steve Naroffc4474992007-08-21 21:17:12 +0000469void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl) {
470 assert(Tok.getKind() == tok::l_brace && "expected {");
471
472 SourceLocation LBraceLoc = ConsumeBrace(); // the "{"
473 llvm::SmallVector<DeclTy*, 32> IvarDecls;
474
475 // While we still have something to read, read the instance variables.
476 while (Tok.getKind() != tok::r_brace &&
477 Tok.getKind() != tok::eof) {
478 // Each iteration of this loop reads one objc-instance-variable-decl.
479
480 // Check for extraneous top-level semicolon.
481 if (Tok.getKind() == tok::semi) {
482 Diag(Tok, diag::ext_extra_struct_semi);
483 ConsumeToken();
484 continue;
485 }
486 // Set the default visibility to private.
487 tok::ObjCKeywordKind visibility = tok::objc_private;
488 if (Tok.getKind() == tok::at) { // parse objc-visibility-spec
489 ConsumeToken(); // eat the @ sign
Steve Naroff87c329f2007-08-23 18:16:40 +0000490 switch (Tok.getObjCKeywordID()) {
Steve Naroffc4474992007-08-21 21:17:12 +0000491 case tok::objc_private:
492 case tok::objc_public:
493 case tok::objc_protected:
494 case tok::objc_package:
Steve Naroff87c329f2007-08-23 18:16:40 +0000495 visibility = Tok.getObjCKeywordID();
Steve Naroffc4474992007-08-21 21:17:12 +0000496 ConsumeToken();
497 continue;
498 default:
499 Diag(Tok, diag::err_objc_illegal_visibility_spec);
500 ConsumeToken();
501 continue;
502 }
503 }
504 ParseStructDeclaration(interfaceDecl, IvarDecls);
505
506 if (Tok.getKind() == tok::semi) {
507 ConsumeToken();
508 } else if (Tok.getKind() == tok::r_brace) {
509 Diag(Tok.getLocation(), diag::ext_expected_semi_decl_list);
510 break;
511 } else {
512 Diag(Tok, diag::err_expected_semi_decl_list);
513 // Skip to end of block or statement
514 SkipUntil(tok::r_brace, true, true);
515 }
516 }
517 MatchRHSPunctuation(tok::r_brace, LBraceLoc);
518 return;
Chris Lattner4b009652007-07-25 00:24:17 +0000519}
Steve Narofffb367882007-08-20 21:31:48 +0000520
521/// objc-protocol-declaration:
522/// objc-protocol-definition
523/// objc-protocol-forward-reference
524///
525/// objc-protocol-definition:
526/// @protocol identifier
527/// objc-protocol-refs[opt]
528/// objc-methodprotolist
529/// @end
530///
531/// objc-protocol-forward-reference:
532/// @protocol identifier-list ';'
533///
534/// "@protocol identifier ;" should be resolved as "@protocol
535/// identifier-list ;": objc-methodprotolist may not start with a
536/// semicolon in the first alternative if objc-protocol-refs are omitted.
537
Steve Naroff72f17fb2007-08-22 22:17:26 +0000538Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) {
Steve Naroff87c329f2007-08-23 18:16:40 +0000539 assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
Steve Naroff72f17fb2007-08-22 22:17:26 +0000540 "ParseObjCAtProtocolDeclaration(): Expected @protocol");
541 ConsumeToken(); // the "protocol" identifier
542
543 if (Tok.getKind() != tok::identifier) {
544 Diag(Tok, diag::err_expected_ident); // missing protocol name.
545 return 0;
546 }
547 // Save the protocol name, then consume it.
548 IdentifierInfo *protocolName = Tok.getIdentifierInfo();
549 SourceLocation nameLoc = ConsumeToken();
550
551 if (Tok.getKind() == tok::semi) { // forward declaration.
552 ConsumeToken();
553 return 0; // FIXME: add protocolName
554 }
555 if (Tok.getKind() == tok::comma) { // list of forward declarations.
556 // Parse the list of forward declarations.
557 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
558 ProtocolRefs.push_back(protocolName);
559
560 while (1) {
561 ConsumeToken(); // the ','
562 if (Tok.getKind() != tok::identifier) {
563 Diag(Tok, diag::err_expected_ident);
564 SkipUntil(tok::semi);
565 return 0;
566 }
567 ProtocolRefs.push_back(Tok.getIdentifierInfo());
568 ConsumeToken(); // the identifier
569
570 if (Tok.getKind() != tok::comma)
571 break;
572 }
573 // Consume the ';'.
574 if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
575 return 0;
576 return 0; // FIXME
577 }
578 // Last, and definitely not least, parse a protocol declaration.
579 if (Tok.getKind() == tok::less) {
580 if (ParseObjCProtocolReferences())
581 return 0;
582 }
583 ParseObjCInterfaceDeclList(0/*FIXME*/);
584
585 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
Steve Naroff87c329f2007-08-23 18:16:40 +0000586 if (Tok.isObjCAtKeyword(tok::objc_end)) {
Steve Naroff72f17fb2007-08-22 22:17:26 +0000587 ConsumeToken(); // the "end" identifier
588 return 0;
589 }
590 Diag(Tok, diag::err_objc_missing_end);
Steve Narofffb367882007-08-20 21:31:48 +0000591 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000592}
Steve Narofffb367882007-08-20 21:31:48 +0000593
594/// objc-implementation:
595/// objc-class-implementation-prologue
596/// objc-category-implementation-prologue
597///
598/// objc-class-implementation-prologue:
599/// @implementation identifier objc-superclass[opt]
600/// objc-class-instance-variables[opt]
601///
602/// objc-category-implementation-prologue:
603/// @implementation identifier ( identifier )
604
605Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000606 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000607 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000608}
Steve Narofffb367882007-08-20 21:31:48 +0000609Parser::DeclTy *Parser::ParseObjCAtEndDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000610 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000611 return 0;
612}
613Parser::DeclTy *Parser::ParseObjCAtAliasDeclaration() {
614 assert(0 && "Unimp");
615 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000616}
617
Steve Naroff72f17fb2007-08-22 22:17:26 +0000618void Parser::ParseObjCInstanceMethodDefinition() {
619 assert(0 && "Parser::ParseObjCInstanceMethodDefinition():: Unimp");
Chris Lattner4b009652007-07-25 00:24:17 +0000620}
621
Steve Naroff72f17fb2007-08-22 22:17:26 +0000622void Parser::ParseObjCClassMethodDefinition() {
623 assert(0 && "Parser::ParseObjCClassMethodDefinition():: Unimp");
Chris Lattner4b009652007-07-25 00:24:17 +0000624}
Anders Carlssona66cad42007-08-21 17:43:55 +0000625
626Parser::ExprResult Parser::ParseObjCExpression() {
627 SourceLocation AtLoc = ConsumeToken(); // the "@"
628
629 switch (Tok.getKind()) {
630 case tok::string_literal: // primary-expression: string-literal
631 case tok::wide_string_literal:
632 return ParseObjCStringLiteral();
Anders Carlsson2996b4e2007-08-23 15:25:28 +0000633 default:
634 break;
635 }
636
637 switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
Anders Carlsson8be1d402007-08-22 15:14:15 +0000638 case tok::objc_encode:
639 return ParseObjCEncodeExpression();
Anders Carlsson2996b4e2007-08-23 15:25:28 +0000640 case tok::objc_protocol:
641 return ParseObjCProtocolExpression();
Anders Carlssona66cad42007-08-21 17:43:55 +0000642 default:
643 Diag(AtLoc, diag::err_unexpected_at);
644 SkipUntil(tok::semi);
645 break;
646 }
647
648 return 0;
649}
650
651Parser::ExprResult Parser::ParseObjCStringLiteral() {
652 ExprResult Res = ParseStringLiteralExpression();
653
654 if (Res.isInvalid) return Res;
655
656 return Actions.ParseObjCStringLiteral(Res.Val);
657}
Anders Carlsson8be1d402007-08-22 15:14:15 +0000658
659/// objc-encode-expression:
660/// @encode ( type-name )
661Parser::ExprResult Parser::ParseObjCEncodeExpression() {
Steve Naroff87c329f2007-08-23 18:16:40 +0000662 assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
Anders Carlsson8be1d402007-08-22 15:14:15 +0000663
664 SourceLocation EncLoc = ConsumeToken();
665
666 if (Tok.getKind() != tok::l_paren) {
667 Diag(Tok, diag::err_expected_lparen_after, "@encode");
668 return true;
669 }
670
671 SourceLocation LParenLoc = ConsumeParen();
672
673 TypeTy *Ty = ParseTypeName();
674
Anders Carlsson92faeb82007-08-23 15:31:37 +0000675 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
Anders Carlsson8be1d402007-08-22 15:14:15 +0000676
677 return Actions.ParseObjCEncodeExpression(EncLoc, LParenLoc, Ty,
Anders Carlsson92faeb82007-08-23 15:31:37 +0000678 RParenLoc);
Anders Carlsson8be1d402007-08-22 15:14:15 +0000679}
Anders Carlsson2996b4e2007-08-23 15:25:28 +0000680
681/// objc-protocol-expression
682/// @protocol ( protocol-name )
683
684Parser::ExprResult Parser::ParseObjCProtocolExpression()
685{
686 SourceLocation ProtoLoc = ConsumeToken();
687
688 if (Tok.getKind() != tok::l_paren) {
689 Diag(Tok, diag::err_expected_lparen_after, "@protocol");
690 return true;
691 }
692
693 SourceLocation LParenLoc = ConsumeParen();
694
695 if (Tok.getKind() != tok::identifier) {
696 Diag(Tok, diag::err_expected_ident);
697 return true;
698 }
699
700 // FIXME: Do something with the protocol name
701 ConsumeToken();
702
Anders Carlsson92faeb82007-08-23 15:31:37 +0000703 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
Anders Carlsson2996b4e2007-08-23 15:25:28 +0000704
705 // FIXME
706 return 0;
707}