blob: 7c0f84257eb973a2fa4bcf9d55c59aa2f8013414 [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///
Steve Naroffa8ee2262007-08-22 23:18:22 +0000306bool Parser::isObjCTypeQualifier() {
307 if (Tok.getKind() == tok::identifier) {
Chris Lattner32352462007-08-29 22:54:08 +0000308 const IdentifierInfo *II = Tok.getIdentifierInfo();
309 for (unsigned i = 0; i < objc_NumQuals; ++i)
310 if (II == ObjcTypeQuals[i]) return true;
Steve Naroffa8ee2262007-08-22 23:18:22 +0000311 }
312 return false;
313}
314
Steve Naroff0bbffd82007-08-22 16:35:03 +0000315/// objc-type-name:
316/// '(' objc-type-qualifiers[opt] type-name ')'
317/// '(' objc-type-qualifiers[opt] ')'
318///
319/// objc-type-qualifiers:
320/// objc-type-qualifier
321/// objc-type-qualifiers objc-type-qualifier
322///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000323void Parser::ParseObjCTypeName() {
324 assert(Tok.getKind() == tok::l_paren && "expected (");
325
326 SourceLocation LParenLoc = ConsumeParen(), RParenLoc;
327
Steve Naroffa8ee2262007-08-22 23:18:22 +0000328 while (isObjCTypeQualifier())
329 ConsumeToken();
330
Steve Naroff0bbffd82007-08-22 16:35:03 +0000331 if (isTypeSpecifierQualifier()) {
Steve Naroff72f17fb2007-08-22 22:17:26 +0000332 //TypeTy *Ty = ParseTypeName();
333 //assert(Ty && "Parser::ParseObjCTypeName(): missing type");
334 ParseTypeName(); // FIXME: when sema support is added.
Steve Naroff0bbffd82007-08-22 16:35:03 +0000335 }
336 if (Tok.getKind() != tok::r_paren) {
337 MatchRHSPunctuation(tok::r_paren, LParenLoc);
338 return;
339 }
340 RParenLoc = ConsumeParen();
341}
342
343/// objc-method-decl:
344/// objc-selector
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000345/// objc-keyword-selector objc-parmlist[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000346/// objc-type-name objc-selector
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000347/// objc-type-name objc-keyword-selector objc-parmlist[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000348///
349/// objc-keyword-selector:
Steve Naroff72f17fb2007-08-22 22:17:26 +0000350/// objc-keyword-decl
Steve Naroff0bbffd82007-08-22 16:35:03 +0000351/// objc-keyword-selector objc-keyword-decl
352///
353/// objc-keyword-decl:
Steve Naroff72f17fb2007-08-22 22:17:26 +0000354/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
355/// objc-selector ':' objc-keyword-attributes[opt] identifier
356/// ':' objc-type-name objc-keyword-attributes[opt] identifier
357/// ':' objc-keyword-attributes[opt] identifier
Steve Naroff0bbffd82007-08-22 16:35:03 +0000358///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000359/// objc-parmlist:
360/// objc-parms objc-ellipsis[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000361///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000362/// objc-parms:
363/// objc-parms , parameter-declaration
Steve Naroff0bbffd82007-08-22 16:35:03 +0000364///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000365/// objc-ellipsis:
Steve Naroff0bbffd82007-08-22 16:35:03 +0000366/// , ...
367///
Steve Naroff72f17fb2007-08-22 22:17:26 +0000368/// objc-keyword-attributes: [OBJC2]
369/// __attribute__((unused))
370///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000371void Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc) {
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000372
373 // Parse the return type.
Steve Naroff0bbffd82007-08-22 16:35:03 +0000374 if (Tok.getKind() == tok::l_paren)
375 ParseObjCTypeName();
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000376 IdentifierInfo *selIdent = ParseObjCSelector();
377
378 if (Tok.getKind() == tok::colon) {
379 IdentifierInfo *keywordSelector = selIdent;
380 while (1) {
381 // Each iteration parses a single keyword argument.
382 if (Tok.getKind() != tok::colon) {
383 Diag(Tok, diag::err_expected_colon);
384 break;
385 }
386 ConsumeToken(); // Eat the ':'.
387 if (Tok.getKind() == tok::l_paren) // Parse the argument type.
388 ParseObjCTypeName();
Steve Naroff72f17fb2007-08-22 22:17:26 +0000389
390 // If attributes exist before the argument name, parse them.
Steve Naroffa7f62782007-08-23 19:56:30 +0000391 if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
Steve Naroff72f17fb2007-08-22 22:17:26 +0000392 ParseAttributes();
393
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000394 if (Tok.getKind() != tok::identifier) {
395 Diag(Tok, diag::err_expected_ident); // missing argument name.
396 break;
397 }
398 ConsumeToken(); // Eat the identifier.
399 // FIXME: add Actions.BuildObjCKeyword()
400
401 keywordSelector = ParseObjCSelector();
402 if (!keywordSelector && Tok.getKind() != tok::colon)
403 break;
404 // We have a selector or a colon, continue parsing.
405 }
406 // Parse the (optional) parameter list.
407 while (Tok.getKind() == tok::comma) {
408 ConsumeToken();
409 if (Tok.getKind() == tok::ellipsis) {
410 ConsumeToken();
411 break;
412 }
413 ParseDeclaration(Declarator::PrototypeContext);
414 }
415 } else if (!selIdent) {
416 Diag(Tok, diag::err_expected_ident); // missing selector name.
417 }
418 // FIXME: add Actions.BuildMethodSignature().
Steve Naroff0bbffd82007-08-22 16:35:03 +0000419}
420
Steve Narofffb367882007-08-20 21:31:48 +0000421/// objc-protocol-refs:
422/// '<' identifier-list '>'
423///
424bool Parser::ParseObjCProtocolReferences() {
425 assert(Tok.getKind() == tok::less && "expected <");
426
427 ConsumeToken(); // the "<"
428 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
429
430 while (1) {
431 if (Tok.getKind() != tok::identifier) {
432 Diag(Tok, diag::err_expected_ident);
433 SkipUntil(tok::greater);
434 return true;
435 }
436 ProtocolRefs.push_back(Tok.getIdentifierInfo());
437 ConsumeToken();
438
439 if (Tok.getKind() != tok::comma)
440 break;
441 ConsumeToken();
442 }
443 // Consume the '>'.
444 return ExpectAndConsume(tok::greater, diag::err_expected_greater);
445}
446
447/// objc-class-instance-variables:
448/// '{' objc-instance-variable-decl-list[opt] '}'
449///
450/// objc-instance-variable-decl-list:
451/// objc-visibility-spec
452/// objc-instance-variable-decl ';'
453/// ';'
454/// objc-instance-variable-decl-list objc-visibility-spec
455/// objc-instance-variable-decl-list objc-instance-variable-decl ';'
456/// objc-instance-variable-decl-list ';'
457///
458/// objc-visibility-spec:
459/// @private
460/// @protected
461/// @public
Steve Naroffc4474992007-08-21 21:17:12 +0000462/// @package [OBJC2]
Steve Narofffb367882007-08-20 21:31:48 +0000463///
464/// objc-instance-variable-decl:
465/// struct-declaration
466///
Steve Naroffc4474992007-08-21 21:17:12 +0000467void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl) {
468 assert(Tok.getKind() == tok::l_brace && "expected {");
469
470 SourceLocation LBraceLoc = ConsumeBrace(); // the "{"
471 llvm::SmallVector<DeclTy*, 32> IvarDecls;
472
473 // While we still have something to read, read the instance variables.
474 while (Tok.getKind() != tok::r_brace &&
475 Tok.getKind() != tok::eof) {
476 // Each iteration of this loop reads one objc-instance-variable-decl.
477
478 // Check for extraneous top-level semicolon.
479 if (Tok.getKind() == tok::semi) {
480 Diag(Tok, diag::ext_extra_struct_semi);
481 ConsumeToken();
482 continue;
483 }
484 // Set the default visibility to private.
485 tok::ObjCKeywordKind visibility = tok::objc_private;
486 if (Tok.getKind() == tok::at) { // parse objc-visibility-spec
487 ConsumeToken(); // eat the @ sign
Steve Naroff87c329f2007-08-23 18:16:40 +0000488 switch (Tok.getObjCKeywordID()) {
Steve Naroffc4474992007-08-21 21:17:12 +0000489 case tok::objc_private:
490 case tok::objc_public:
491 case tok::objc_protected:
492 case tok::objc_package:
Steve Naroff87c329f2007-08-23 18:16:40 +0000493 visibility = Tok.getObjCKeywordID();
Steve Naroffc4474992007-08-21 21:17:12 +0000494 ConsumeToken();
495 continue;
496 default:
497 Diag(Tok, diag::err_objc_illegal_visibility_spec);
498 ConsumeToken();
499 continue;
500 }
501 }
502 ParseStructDeclaration(interfaceDecl, IvarDecls);
503
504 if (Tok.getKind() == tok::semi) {
505 ConsumeToken();
506 } else if (Tok.getKind() == tok::r_brace) {
507 Diag(Tok.getLocation(), diag::ext_expected_semi_decl_list);
508 break;
509 } else {
510 Diag(Tok, diag::err_expected_semi_decl_list);
511 // Skip to end of block or statement
512 SkipUntil(tok::r_brace, true, true);
513 }
514 }
515 MatchRHSPunctuation(tok::r_brace, LBraceLoc);
516 return;
Chris Lattner4b009652007-07-25 00:24:17 +0000517}
Steve Narofffb367882007-08-20 21:31:48 +0000518
519/// objc-protocol-declaration:
520/// objc-protocol-definition
521/// objc-protocol-forward-reference
522///
523/// objc-protocol-definition:
524/// @protocol identifier
525/// objc-protocol-refs[opt]
526/// objc-methodprotolist
527/// @end
528///
529/// objc-protocol-forward-reference:
530/// @protocol identifier-list ';'
531///
532/// "@protocol identifier ;" should be resolved as "@protocol
533/// identifier-list ;": objc-methodprotolist may not start with a
534/// semicolon in the first alternative if objc-protocol-refs are omitted.
535
Steve Naroff72f17fb2007-08-22 22:17:26 +0000536Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) {
Steve Naroff87c329f2007-08-23 18:16:40 +0000537 assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
Steve Naroff72f17fb2007-08-22 22:17:26 +0000538 "ParseObjCAtProtocolDeclaration(): Expected @protocol");
539 ConsumeToken(); // the "protocol" identifier
540
541 if (Tok.getKind() != tok::identifier) {
542 Diag(Tok, diag::err_expected_ident); // missing protocol name.
543 return 0;
544 }
545 // Save the protocol name, then consume it.
546 IdentifierInfo *protocolName = Tok.getIdentifierInfo();
547 SourceLocation nameLoc = ConsumeToken();
548
549 if (Tok.getKind() == tok::semi) { // forward declaration.
550 ConsumeToken();
551 return 0; // FIXME: add protocolName
552 }
553 if (Tok.getKind() == tok::comma) { // list of forward declarations.
554 // Parse the list of forward declarations.
555 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
556 ProtocolRefs.push_back(protocolName);
557
558 while (1) {
559 ConsumeToken(); // the ','
560 if (Tok.getKind() != tok::identifier) {
561 Diag(Tok, diag::err_expected_ident);
562 SkipUntil(tok::semi);
563 return 0;
564 }
565 ProtocolRefs.push_back(Tok.getIdentifierInfo());
566 ConsumeToken(); // the identifier
567
568 if (Tok.getKind() != tok::comma)
569 break;
570 }
571 // Consume the ';'.
572 if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
573 return 0;
574 return 0; // FIXME
575 }
576 // Last, and definitely not least, parse a protocol declaration.
577 if (Tok.getKind() == tok::less) {
578 if (ParseObjCProtocolReferences())
579 return 0;
580 }
581 ParseObjCInterfaceDeclList(0/*FIXME*/);
582
583 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
Steve Naroff87c329f2007-08-23 18:16:40 +0000584 if (Tok.isObjCAtKeyword(tok::objc_end)) {
Steve Naroff72f17fb2007-08-22 22:17:26 +0000585 ConsumeToken(); // the "end" identifier
586 return 0;
587 }
588 Diag(Tok, diag::err_objc_missing_end);
Steve Narofffb367882007-08-20 21:31:48 +0000589 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000590}
Steve Narofffb367882007-08-20 21:31:48 +0000591
592/// objc-implementation:
593/// objc-class-implementation-prologue
594/// objc-category-implementation-prologue
595///
596/// objc-class-implementation-prologue:
597/// @implementation identifier objc-superclass[opt]
598/// objc-class-instance-variables[opt]
599///
600/// objc-category-implementation-prologue:
601/// @implementation identifier ( identifier )
602
603Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000604 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000605 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000606}
Steve Narofffb367882007-08-20 21:31:48 +0000607Parser::DeclTy *Parser::ParseObjCAtEndDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000608 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000609 return 0;
610}
611Parser::DeclTy *Parser::ParseObjCAtAliasDeclaration() {
612 assert(0 && "Unimp");
613 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000614}
615
Steve Naroff72f17fb2007-08-22 22:17:26 +0000616void Parser::ParseObjCInstanceMethodDefinition() {
617 assert(0 && "Parser::ParseObjCInstanceMethodDefinition():: Unimp");
Chris Lattner4b009652007-07-25 00:24:17 +0000618}
619
Steve Naroff72f17fb2007-08-22 22:17:26 +0000620void Parser::ParseObjCClassMethodDefinition() {
621 assert(0 && "Parser::ParseObjCClassMethodDefinition():: Unimp");
Chris Lattner4b009652007-07-25 00:24:17 +0000622}
Anders Carlssona66cad42007-08-21 17:43:55 +0000623
624Parser::ExprResult Parser::ParseObjCExpression() {
625 SourceLocation AtLoc = ConsumeToken(); // the "@"
626
627 switch (Tok.getKind()) {
628 case tok::string_literal: // primary-expression: string-literal
629 case tok::wide_string_literal:
630 return ParseObjCStringLiteral();
Anders Carlsson2996b4e2007-08-23 15:25:28 +0000631 default:
632 break;
633 }
634
635 switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
Anders Carlsson8be1d402007-08-22 15:14:15 +0000636 case tok::objc_encode:
637 return ParseObjCEncodeExpression();
Anders Carlsson2996b4e2007-08-23 15:25:28 +0000638 case tok::objc_protocol:
639 return ParseObjCProtocolExpression();
Anders Carlssona66cad42007-08-21 17:43:55 +0000640 default:
641 Diag(AtLoc, diag::err_unexpected_at);
642 SkipUntil(tok::semi);
643 break;
644 }
645
646 return 0;
647}
648
649Parser::ExprResult Parser::ParseObjCStringLiteral() {
650 ExprResult Res = ParseStringLiteralExpression();
651
652 if (Res.isInvalid) return Res;
653
654 return Actions.ParseObjCStringLiteral(Res.Val);
655}
Anders Carlsson8be1d402007-08-22 15:14:15 +0000656
657/// objc-encode-expression:
658/// @encode ( type-name )
659Parser::ExprResult Parser::ParseObjCEncodeExpression() {
Steve Naroff87c329f2007-08-23 18:16:40 +0000660 assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
Anders Carlsson8be1d402007-08-22 15:14:15 +0000661
662 SourceLocation EncLoc = ConsumeToken();
663
664 if (Tok.getKind() != tok::l_paren) {
665 Diag(Tok, diag::err_expected_lparen_after, "@encode");
666 return true;
667 }
668
669 SourceLocation LParenLoc = ConsumeParen();
670
671 TypeTy *Ty = ParseTypeName();
672
Anders Carlsson92faeb82007-08-23 15:31:37 +0000673 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
Anders Carlsson8be1d402007-08-22 15:14:15 +0000674
675 return Actions.ParseObjCEncodeExpression(EncLoc, LParenLoc, Ty,
Anders Carlsson92faeb82007-08-23 15:31:37 +0000676 RParenLoc);
Anders Carlsson8be1d402007-08-22 15:14:15 +0000677}
Anders Carlsson2996b4e2007-08-23 15:25:28 +0000678
679/// objc-protocol-expression
680/// @protocol ( protocol-name )
681
682Parser::ExprResult Parser::ParseObjCProtocolExpression()
683{
684 SourceLocation ProtoLoc = ConsumeToken();
685
686 if (Tok.getKind() != tok::l_paren) {
687 Diag(Tok, diag::err_expected_lparen_after, "@protocol");
688 return true;
689 }
690
691 SourceLocation LParenLoc = ConsumeParen();
692
693 if (Tok.getKind() != tok::identifier) {
694 Diag(Tok, diag::err_expected_ident);
695 return true;
696 }
697
698 // FIXME: Do something with the protocol name
699 ConsumeToken();
700
Anders Carlsson92faeb82007-08-23 15:31:37 +0000701 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
Anders Carlsson2996b4e2007-08-23 15:25:28 +0000702
703 // FIXME
704 return 0;
705}