blob: 4f4bdfe01244aa65b8749dfabaefb4c9517e3acd [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
32 IdentifierInfo *II = Tok.getIdentifierInfo();
33 switch (II ? II->getObjCKeywordID() : tok::objc_not_keyword) {
34 case tok::objc_class:
35 return ParseObjCAtClassDeclaration(AtLoc);
36 case tok::objc_interface:
Steve Narofffb367882007-08-20 21:31:48 +000037 return ParseObjCAtInterfaceDeclaration(AtLoc);
Chris Lattner4b009652007-07-25 00:24:17 +000038 case tok::objc_protocol:
Steve Naroff72f17fb2007-08-22 22:17:26 +000039 return ParseObjCAtProtocolDeclaration(AtLoc);
Chris Lattner4b009652007-07-25 00:24:17 +000040 case tok::objc_implementation:
41 return ParseObjCAtImplementationDeclaration();
42 case tok::objc_end:
43 return ParseObjCAtEndDeclaration();
44 case tok::objc_compatibility_alias:
45 return ParseObjCAtAliasDeclaration();
46 default:
47 Diag(AtLoc, diag::err_unexpected_at);
48 SkipUntil(tok::semi);
Steve Narofffb367882007-08-20 21:31:48 +000049 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +000050 }
51}
52
53///
54/// objc-class-declaration:
55/// '@' 'class' identifier-list ';'
56///
Steve Narofffb367882007-08-20 21:31:48 +000057Parser::DeclTy *Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
Chris Lattner4b009652007-07-25 00:24:17 +000058 ConsumeToken(); // the identifier "class"
59 llvm::SmallVector<IdentifierInfo *, 8> ClassNames;
60
61 while (1) {
62 if (Tok.getKind() != tok::identifier) {
63 Diag(Tok, diag::err_expected_ident);
64 SkipUntil(tok::semi);
Steve Narofffb367882007-08-20 21:31:48 +000065 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +000066 }
Chris Lattner4b009652007-07-25 00:24:17 +000067 ClassNames.push_back(Tok.getIdentifierInfo());
68 ConsumeToken();
69
70 if (Tok.getKind() != tok::comma)
71 break;
72
73 ConsumeToken();
74 }
75
76 // Consume the ';'.
77 if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
Steve Narofffb367882007-08-20 21:31:48 +000078 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +000079
Steve Narofffb367882007-08-20 21:31:48 +000080 return Actions.ParsedObjcClassDeclaration(CurScope,
81 &ClassNames[0], ClassNames.size());
Chris Lattner4b009652007-07-25 00:24:17 +000082}
83
Steve Narofffb367882007-08-20 21:31:48 +000084///
85/// objc-interface:
86/// objc-class-interface-attributes[opt] objc-class-interface
87/// objc-category-interface
88///
89/// objc-class-interface:
90/// '@' 'interface' identifier objc-superclass[opt]
91/// objc-protocol-refs[opt]
92/// objc-class-instance-variables[opt]
93/// objc-interface-decl-list
94/// @end
95///
96/// objc-category-interface:
97/// '@' 'interface' identifier '(' identifier[opt] ')'
98/// objc-protocol-refs[opt]
99/// objc-interface-decl-list
100/// @end
101///
102/// objc-superclass:
103/// ':' identifier
104///
105/// objc-class-interface-attributes:
106/// __attribute__((visibility("default")))
107/// __attribute__((visibility("hidden")))
108/// __attribute__((deprecated))
109/// __attribute__((unavailable))
110/// __attribute__((objc_exception)) - used by NSException on 64-bit
111///
112Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration(
113 SourceLocation atLoc, AttributeList *attrList) {
Steve Naroff72f17fb2007-08-22 22:17:26 +0000114 assert((Tok.getKind() == tok::identifier &&
115 Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_interface) &&
Steve Narofffb367882007-08-20 21:31:48 +0000116 "ParseObjCAtInterfaceDeclaration(): Expected @interface");
117 ConsumeToken(); // the "interface" identifier
118
119 if (Tok.getKind() != tok::identifier) {
120 Diag(Tok, diag::err_expected_ident); // missing class or category name.
121 return 0;
122 }
123 // We have a class or category name - consume it.
Steve Naroff72f17fb2007-08-22 22:17:26 +0000124 IdentifierInfo *nameId = Tok.getIdentifierInfo();
Steve Narofffb367882007-08-20 21:31:48 +0000125 SourceLocation nameLoc = ConsumeToken();
126
127 if (Tok.getKind() == tok::l_paren) { // we have a category
128 SourceLocation lparenLoc = ConsumeParen();
129 SourceLocation categoryLoc, rparenLoc;
130 IdentifierInfo *categoryId = 0;
131
132 // OBJC2: The cateogry name is optional (not an error).
133 if (Tok.getKind() == tok::identifier) {
134 categoryId = Tok.getIdentifierInfo();
135 categoryLoc = ConsumeToken();
136 }
137 if (Tok.getKind() != tok::r_paren) {
138 Diag(Tok, diag::err_expected_rparen);
139 SkipUntil(tok::r_paren, false); // don't stop at ';'
140 return 0;
141 }
142 rparenLoc = ConsumeParen();
143 // Next, we need to check for any protocol references.
144 if (Tok.getKind() == tok::less) {
145 if (ParseObjCProtocolReferences())
146 return 0;
147 }
148 if (attrList) // categories don't support attributes.
149 Diag(Tok, diag::err_objc_no_attributes_on_category);
150
Steve Naroff0bbffd82007-08-22 16:35:03 +0000151 ParseObjCInterfaceDeclList(0/*FIXME*/);
Steve Narofffb367882007-08-20 21:31:48 +0000152
Steve Naroff0bbffd82007-08-22 16:35:03 +0000153 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
154 if (Tok.getKind() == tok::identifier &&
155 Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_end) {
156 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().
192 if (Tok.getKind() == tok::identifier &&
193 Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_end) {
194 ConsumeToken(); // the "end" identifier
Steve Narofffb367882007-08-20 21:31:48 +0000195 return 0;
196 }
Steve Naroff0bbffd82007-08-22 16:35:03 +0000197 Diag(Tok, diag::err_objc_missing_end);
Steve Narofffb367882007-08-20 21:31:48 +0000198 return 0;
199}
200
201/// objc-interface-decl-list:
202/// empty
Steve Narofffb367882007-08-20 21:31:48 +0000203/// objc-interface-decl-list objc-property-decl [OBJC2]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000204/// objc-interface-decl-list objc-method-requirement [OBJC2]
205/// objc-interface-decl-list objc-method-proto
Steve Narofffb367882007-08-20 21:31:48 +0000206/// objc-interface-decl-list declaration
207/// objc-interface-decl-list ';'
208///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000209/// objc-method-requirement: [OBJC2]
210/// @required
211/// @optional
212///
213void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl) {
214 while (1) {
215 if (Tok.getKind() == tok::at) {
216 SourceLocation AtLoc = ConsumeToken(); // the "@"
217 tok::ObjCKeywordKind ocKind = Tok.getIdentifierInfo()->getObjCKeywordID();
218
219 if (ocKind == tok::objc_end) { // terminate list
220 return;
221 } else if (ocKind == tok::objc_required) { // protocols only
222 ConsumeToken();
223 continue;
224 } else if (ocKind == tok::objc_optional) { // protocols only
225 ConsumeToken();
226 continue;
227 } else if (ocKind == tok::objc_property) {
228 ParseObjCPropertyDecl(AtLoc);
229 continue;
230 } else {
231 Diag(Tok, diag::err_objc_illegal_interface_qual);
232 ConsumeToken();
233 }
234 }
235 if (Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) {
236 ParseObjCMethodPrototype();
237 continue;
238 }
239 if (Tok.getKind() == tok::semi)
240 ConsumeToken();
241 else if (Tok.getKind() == tok::eof)
242 return;
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000243 else
244 // FIXME: as the name implies, this rule allows function definitions.
245 // We could pass a flag or check for functions during semantic analysis.
Steve Naroff0bbffd82007-08-22 16:35:03 +0000246 ParseDeclarationOrFunctionDefinition();
247 }
248}
249
250void Parser::ParseObjCPropertyDecl(SourceLocation atLoc) {
Chris Lattner4b009652007-07-25 00:24:17 +0000251 assert(0 && "Unimp");
252}
Steve Narofffb367882007-08-20 21:31:48 +0000253
Steve Naroff0bbffd82007-08-22 16:35:03 +0000254/// objc-methodproto:
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000255/// objc-instance-method objc-method-decl objc-method-attributes[opt] ';'
256/// objc-class-method objc-method-decl objc-method-attributes[opt] ';'
Steve Naroff0bbffd82007-08-22 16:35:03 +0000257///
258/// objc-instance-method: '-'
259/// objc-class-method: '+'
260///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000261/// objc-method-attributes: [OBJC2]
262/// __attribute__((deprecated))
263///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000264void Parser::ParseObjCMethodPrototype() {
265 assert((Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) &&
266 "expected +/-");
267
268 tok::TokenKind methodType = Tok.getKind();
269 SourceLocation methodLoc = ConsumeToken();
270
271 // FIXME: deal with "context sensitive" protocol qualifiers in prototypes
272 ParseObjCMethodDecl(methodType, methodLoc);
273
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000274 // If attributes exist after the method, parse them.
275 if (Tok.getKind() == tok::kw___attribute)
276 ParseAttributes();
277
Steve Naroff0bbffd82007-08-22 16:35:03 +0000278 // Consume the ';'.
279 ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "method proto");
280}
281
282/// objc-selector:
283/// identifier
284/// one of
285/// enum struct union if else while do for switch case default
286/// break continue return goto asm sizeof typeof __alignof
287/// unsigned long const short volatile signed restrict _Complex
288/// in out inout bycopy byref oneway int char float double void _Bool
289///
290IdentifierInfo *Parser::ParseObjCSelector() {
291 tok::TokenKind tKind = Tok.getKind();
292 IdentifierInfo *II = 0;
293
294 if (tKind == tok::identifier ||
295 (tKind >= tok::kw_auto && tKind <= tok::kw__Complex)) {
296 // FIXME: make sure the list of keywords jives with gcc. For example,
297 // the above test does not include in/out/inout/bycopy/byref/oneway.
298 II = Tok.getIdentifierInfo();
299 ConsumeToken();
300 }
301 return II;
302}
303
Steve Naroffa8ee2262007-08-22 23:18:22 +0000304/// objc-type-qualifier: one of
305/// in out inout bycopy byref oneway
306///
307/// FIXME: remove the string compares...
308bool Parser::isObjCTypeQualifier() {
309 if (Tok.getKind() == tok::identifier) {
310 const char *qual = Tok.getIdentifierInfo()->getName();
311 return (strcmp(qual, "in") == 0) || (strcmp(qual, "out") == 0) ||
312 (strcmp(qual, "inout") == 0) || (strcmp(qual, "oneway") == 0) ||
313 (strcmp(qual, "bycopy") == 0) || (strcmp(qual, "byref") == 0);
314 }
315 return false;
316}
317
Steve Naroff0bbffd82007-08-22 16:35:03 +0000318/// objc-type-name:
319/// '(' objc-type-qualifiers[opt] type-name ')'
320/// '(' objc-type-qualifiers[opt] ')'
321///
322/// objc-type-qualifiers:
323/// objc-type-qualifier
324/// objc-type-qualifiers objc-type-qualifier
325///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000326void Parser::ParseObjCTypeName() {
327 assert(Tok.getKind() == tok::l_paren && "expected (");
328
329 SourceLocation LParenLoc = ConsumeParen(), RParenLoc;
330
Steve Naroffa8ee2262007-08-22 23:18:22 +0000331 while (isObjCTypeQualifier())
332 ConsumeToken();
333
Steve Naroff0bbffd82007-08-22 16:35:03 +0000334 if (isTypeSpecifierQualifier()) {
Steve Naroff72f17fb2007-08-22 22:17:26 +0000335 //TypeTy *Ty = ParseTypeName();
336 //assert(Ty && "Parser::ParseObjCTypeName(): missing type");
337 ParseTypeName(); // FIXME: when sema support is added.
Steve Naroff0bbffd82007-08-22 16:35:03 +0000338 }
339 if (Tok.getKind() != tok::r_paren) {
340 MatchRHSPunctuation(tok::r_paren, LParenLoc);
341 return;
342 }
343 RParenLoc = ConsumeParen();
344}
345
346/// objc-method-decl:
347/// objc-selector
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000348/// objc-keyword-selector objc-parmlist[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000349/// objc-type-name objc-selector
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000350/// objc-type-name objc-keyword-selector objc-parmlist[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000351///
352/// objc-keyword-selector:
Steve Naroff72f17fb2007-08-22 22:17:26 +0000353/// objc-keyword-decl
Steve Naroff0bbffd82007-08-22 16:35:03 +0000354/// objc-keyword-selector objc-keyword-decl
355///
356/// objc-keyword-decl:
Steve Naroff72f17fb2007-08-22 22:17:26 +0000357/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
358/// objc-selector ':' objc-keyword-attributes[opt] identifier
359/// ':' objc-type-name objc-keyword-attributes[opt] identifier
360/// ':' objc-keyword-attributes[opt] identifier
Steve Naroff0bbffd82007-08-22 16:35:03 +0000361///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000362/// objc-parmlist:
363/// objc-parms objc-ellipsis[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000364///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000365/// objc-parms:
366/// objc-parms , parameter-declaration
Steve Naroff0bbffd82007-08-22 16:35:03 +0000367///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000368/// objc-ellipsis:
Steve Naroff0bbffd82007-08-22 16:35:03 +0000369/// , ...
370///
Steve Naroff72f17fb2007-08-22 22:17:26 +0000371/// objc-keyword-attributes: [OBJC2]
372/// __attribute__((unused))
373///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000374void Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc) {
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000375
376 // Parse the return type.
Steve Naroff0bbffd82007-08-22 16:35:03 +0000377 if (Tok.getKind() == tok::l_paren)
378 ParseObjCTypeName();
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000379 IdentifierInfo *selIdent = ParseObjCSelector();
380
381 if (Tok.getKind() == tok::colon) {
382 IdentifierInfo *keywordSelector = selIdent;
383 while (1) {
384 // Each iteration parses a single keyword argument.
385 if (Tok.getKind() != tok::colon) {
386 Diag(Tok, diag::err_expected_colon);
387 break;
388 }
389 ConsumeToken(); // Eat the ':'.
390 if (Tok.getKind() == tok::l_paren) // Parse the argument type.
391 ParseObjCTypeName();
Steve Naroff72f17fb2007-08-22 22:17:26 +0000392
393 // If attributes exist before the argument name, parse them.
394 if (Tok.getKind() == tok::kw___attribute)
395 ParseAttributes();
396
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000397 if (Tok.getKind() != tok::identifier) {
398 Diag(Tok, diag::err_expected_ident); // missing argument name.
399 break;
400 }
401 ConsumeToken(); // Eat the identifier.
402 // FIXME: add Actions.BuildObjCKeyword()
403
404 keywordSelector = ParseObjCSelector();
405 if (!keywordSelector && Tok.getKind() != tok::colon)
406 break;
407 // We have a selector or a colon, continue parsing.
408 }
409 // Parse the (optional) parameter list.
410 while (Tok.getKind() == tok::comma) {
411 ConsumeToken();
412 if (Tok.getKind() == tok::ellipsis) {
413 ConsumeToken();
414 break;
415 }
416 ParseDeclaration(Declarator::PrototypeContext);
417 }
418 } else if (!selIdent) {
419 Diag(Tok, diag::err_expected_ident); // missing selector name.
420 }
421 // FIXME: add Actions.BuildMethodSignature().
Steve Naroff0bbffd82007-08-22 16:35:03 +0000422}
423
Steve Narofffb367882007-08-20 21:31:48 +0000424/// objc-protocol-refs:
425/// '<' identifier-list '>'
426///
427bool Parser::ParseObjCProtocolReferences() {
428 assert(Tok.getKind() == tok::less && "expected <");
429
430 ConsumeToken(); // the "<"
431 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
432
433 while (1) {
434 if (Tok.getKind() != tok::identifier) {
435 Diag(Tok, diag::err_expected_ident);
436 SkipUntil(tok::greater);
437 return true;
438 }
439 ProtocolRefs.push_back(Tok.getIdentifierInfo());
440 ConsumeToken();
441
442 if (Tok.getKind() != tok::comma)
443 break;
444 ConsumeToken();
445 }
446 // Consume the '>'.
447 return ExpectAndConsume(tok::greater, diag::err_expected_greater);
448}
449
450/// objc-class-instance-variables:
451/// '{' objc-instance-variable-decl-list[opt] '}'
452///
453/// objc-instance-variable-decl-list:
454/// objc-visibility-spec
455/// objc-instance-variable-decl ';'
456/// ';'
457/// objc-instance-variable-decl-list objc-visibility-spec
458/// objc-instance-variable-decl-list objc-instance-variable-decl ';'
459/// objc-instance-variable-decl-list ';'
460///
461/// objc-visibility-spec:
462/// @private
463/// @protected
464/// @public
Steve Naroffc4474992007-08-21 21:17:12 +0000465/// @package [OBJC2]
Steve Narofffb367882007-08-20 21:31:48 +0000466///
467/// objc-instance-variable-decl:
468/// struct-declaration
469///
Steve Naroffc4474992007-08-21 21:17:12 +0000470void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl) {
471 assert(Tok.getKind() == tok::l_brace && "expected {");
472
473 SourceLocation LBraceLoc = ConsumeBrace(); // the "{"
474 llvm::SmallVector<DeclTy*, 32> IvarDecls;
475
476 // While we still have something to read, read the instance variables.
477 while (Tok.getKind() != tok::r_brace &&
478 Tok.getKind() != tok::eof) {
479 // Each iteration of this loop reads one objc-instance-variable-decl.
480
481 // Check for extraneous top-level semicolon.
482 if (Tok.getKind() == tok::semi) {
483 Diag(Tok, diag::ext_extra_struct_semi);
484 ConsumeToken();
485 continue;
486 }
487 // Set the default visibility to private.
488 tok::ObjCKeywordKind visibility = tok::objc_private;
489 if (Tok.getKind() == tok::at) { // parse objc-visibility-spec
490 ConsumeToken(); // eat the @ sign
491 IdentifierInfo *specId = Tok.getIdentifierInfo();
492 switch (specId->getObjCKeywordID()) {
493 case tok::objc_private:
494 case tok::objc_public:
495 case tok::objc_protected:
496 case tok::objc_package:
497 visibility = specId->getObjCKeywordID();
498 ConsumeToken();
499 continue;
500 default:
501 Diag(Tok, diag::err_objc_illegal_visibility_spec);
502 ConsumeToken();
503 continue;
504 }
505 }
506 ParseStructDeclaration(interfaceDecl, IvarDecls);
507
508 if (Tok.getKind() == tok::semi) {
509 ConsumeToken();
510 } else if (Tok.getKind() == tok::r_brace) {
511 Diag(Tok.getLocation(), diag::ext_expected_semi_decl_list);
512 break;
513 } else {
514 Diag(Tok, diag::err_expected_semi_decl_list);
515 // Skip to end of block or statement
516 SkipUntil(tok::r_brace, true, true);
517 }
518 }
519 MatchRHSPunctuation(tok::r_brace, LBraceLoc);
520 return;
Chris Lattner4b009652007-07-25 00:24:17 +0000521}
Steve Narofffb367882007-08-20 21:31:48 +0000522
523/// objc-protocol-declaration:
524/// objc-protocol-definition
525/// objc-protocol-forward-reference
526///
527/// objc-protocol-definition:
528/// @protocol identifier
529/// objc-protocol-refs[opt]
530/// objc-methodprotolist
531/// @end
532///
533/// objc-protocol-forward-reference:
534/// @protocol identifier-list ';'
535///
536/// "@protocol identifier ;" should be resolved as "@protocol
537/// identifier-list ;": objc-methodprotolist may not start with a
538/// semicolon in the first alternative if objc-protocol-refs are omitted.
539
Steve Naroff72f17fb2007-08-22 22:17:26 +0000540Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) {
541 assert((Tok.getKind() == tok::identifier &&
542 Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_protocol) &&
543 "ParseObjCAtProtocolDeclaration(): Expected @protocol");
544 ConsumeToken(); // the "protocol" identifier
545
546 if (Tok.getKind() != tok::identifier) {
547 Diag(Tok, diag::err_expected_ident); // missing protocol name.
548 return 0;
549 }
550 // Save the protocol name, then consume it.
551 IdentifierInfo *protocolName = Tok.getIdentifierInfo();
552 SourceLocation nameLoc = ConsumeToken();
553
554 if (Tok.getKind() == tok::semi) { // forward declaration.
555 ConsumeToken();
556 return 0; // FIXME: add protocolName
557 }
558 if (Tok.getKind() == tok::comma) { // list of forward declarations.
559 // Parse the list of forward declarations.
560 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
561 ProtocolRefs.push_back(protocolName);
562
563 while (1) {
564 ConsumeToken(); // the ','
565 if (Tok.getKind() != tok::identifier) {
566 Diag(Tok, diag::err_expected_ident);
567 SkipUntil(tok::semi);
568 return 0;
569 }
570 ProtocolRefs.push_back(Tok.getIdentifierInfo());
571 ConsumeToken(); // the identifier
572
573 if (Tok.getKind() != tok::comma)
574 break;
575 }
576 // Consume the ';'.
577 if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
578 return 0;
579 return 0; // FIXME
580 }
581 // Last, and definitely not least, parse a protocol declaration.
582 if (Tok.getKind() == tok::less) {
583 if (ParseObjCProtocolReferences())
584 return 0;
585 }
586 ParseObjCInterfaceDeclList(0/*FIXME*/);
587
588 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
589 if (Tok.getKind() == tok::identifier &&
590 Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_end) {
591 ConsumeToken(); // the "end" identifier
592 return 0;
593 }
594 Diag(Tok, diag::err_objc_missing_end);
Steve Narofffb367882007-08-20 21:31:48 +0000595 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000596}
Steve Narofffb367882007-08-20 21:31:48 +0000597
598/// objc-implementation:
599/// objc-class-implementation-prologue
600/// objc-category-implementation-prologue
601///
602/// objc-class-implementation-prologue:
603/// @implementation identifier objc-superclass[opt]
604/// objc-class-instance-variables[opt]
605///
606/// objc-category-implementation-prologue:
607/// @implementation identifier ( identifier )
608
609Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000610 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000611 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000612}
Steve Narofffb367882007-08-20 21:31:48 +0000613Parser::DeclTy *Parser::ParseObjCAtEndDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000614 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000615 return 0;
616}
617Parser::DeclTy *Parser::ParseObjCAtAliasDeclaration() {
618 assert(0 && "Unimp");
619 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000620}
621
Steve Naroff72f17fb2007-08-22 22:17:26 +0000622void Parser::ParseObjCInstanceMethodDefinition() {
623 assert(0 && "Parser::ParseObjCInstanceMethodDefinition():: Unimp");
Chris Lattner4b009652007-07-25 00:24:17 +0000624}
625
Steve Naroff72f17fb2007-08-22 22:17:26 +0000626void Parser::ParseObjCClassMethodDefinition() {
627 assert(0 && "Parser::ParseObjCClassMethodDefinition():: Unimp");
Chris Lattner4b009652007-07-25 00:24:17 +0000628}
Anders Carlssona66cad42007-08-21 17:43:55 +0000629
630Parser::ExprResult Parser::ParseObjCExpression() {
631 SourceLocation AtLoc = ConsumeToken(); // the "@"
632
633 switch (Tok.getKind()) {
634 case tok::string_literal: // primary-expression: string-literal
635 case tok::wide_string_literal:
636 return ParseObjCStringLiteral();
Anders Carlsson8be1d402007-08-22 15:14:15 +0000637 case tok::objc_encode:
638 return ParseObjCEncodeExpression();
639 break;
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() {
660 assert(Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_encode &&
661 "Not an @encode expression!");
662
663 SourceLocation EncLoc = ConsumeToken();
664
665 if (Tok.getKind() != tok::l_paren) {
666 Diag(Tok, diag::err_expected_lparen_after, "@encode");
667 return true;
668 }
669
670 SourceLocation LParenLoc = ConsumeParen();
671
672 TypeTy *Ty = ParseTypeName();
673
674 if (Tok.getKind() != tok::r_paren) {
675 Diag(Tok, diag::err_expected_rparen);
676 return true;
677 }
678
679 return Actions.ParseObjCEncodeExpression(EncLoc, LParenLoc, Ty,
680 ConsumeParen());
681}