blob: 4aaaecc7578d234ab741a6df8d97661689541f06 [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
304/// objc-type-name:
305/// '(' objc-type-qualifiers[opt] type-name ')'
306/// '(' objc-type-qualifiers[opt] ')'
307///
308/// objc-type-qualifiers:
309/// objc-type-qualifier
310/// objc-type-qualifiers objc-type-qualifier
311///
312/// objc-type-qualifier: one of
313/// in out inout bycopy byref oneway
314///
315void Parser::ParseObjCTypeName() {
316 assert(Tok.getKind() == tok::l_paren && "expected (");
317
318 SourceLocation LParenLoc = ConsumeParen(), RParenLoc;
319
320 if (isTypeSpecifierQualifier()) {
Steve Naroff72f17fb2007-08-22 22:17:26 +0000321 //TypeTy *Ty = ParseTypeName();
322 //assert(Ty && "Parser::ParseObjCTypeName(): missing type");
323 ParseTypeName(); // FIXME: when sema support is added.
Steve Naroff0bbffd82007-08-22 16:35:03 +0000324 }
325 if (Tok.getKind() != tok::r_paren) {
326 MatchRHSPunctuation(tok::r_paren, LParenLoc);
327 return;
328 }
329 RParenLoc = ConsumeParen();
330}
331
332/// objc-method-decl:
333/// objc-selector
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000334/// objc-keyword-selector objc-parmlist[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000335/// objc-type-name objc-selector
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000336/// objc-type-name objc-keyword-selector objc-parmlist[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000337///
338/// objc-keyword-selector:
Steve Naroff72f17fb2007-08-22 22:17:26 +0000339/// objc-keyword-decl
Steve Naroff0bbffd82007-08-22 16:35:03 +0000340/// objc-keyword-selector objc-keyword-decl
341///
342/// objc-keyword-decl:
Steve Naroff72f17fb2007-08-22 22:17:26 +0000343/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
344/// objc-selector ':' objc-keyword-attributes[opt] identifier
345/// ':' objc-type-name objc-keyword-attributes[opt] identifier
346/// ':' objc-keyword-attributes[opt] identifier
Steve Naroff0bbffd82007-08-22 16:35:03 +0000347///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000348/// objc-parmlist:
349/// objc-parms objc-ellipsis[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000350///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000351/// objc-parms:
352/// objc-parms , parameter-declaration
Steve Naroff0bbffd82007-08-22 16:35:03 +0000353///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000354/// objc-ellipsis:
Steve Naroff0bbffd82007-08-22 16:35:03 +0000355/// , ...
356///
Steve Naroff72f17fb2007-08-22 22:17:26 +0000357/// objc-keyword-attributes: [OBJC2]
358/// __attribute__((unused))
359///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000360void Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc) {
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000361
362 // Parse the return type.
Steve Naroff0bbffd82007-08-22 16:35:03 +0000363 if (Tok.getKind() == tok::l_paren)
364 ParseObjCTypeName();
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000365 IdentifierInfo *selIdent = ParseObjCSelector();
366
367 if (Tok.getKind() == tok::colon) {
368 IdentifierInfo *keywordSelector = selIdent;
369 while (1) {
370 // Each iteration parses a single keyword argument.
371 if (Tok.getKind() != tok::colon) {
372 Diag(Tok, diag::err_expected_colon);
373 break;
374 }
375 ConsumeToken(); // Eat the ':'.
376 if (Tok.getKind() == tok::l_paren) // Parse the argument type.
377 ParseObjCTypeName();
Steve Naroff72f17fb2007-08-22 22:17:26 +0000378
379 // If attributes exist before the argument name, parse them.
380 if (Tok.getKind() == tok::kw___attribute)
381 ParseAttributes();
382
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000383 if (Tok.getKind() != tok::identifier) {
384 Diag(Tok, diag::err_expected_ident); // missing argument name.
385 break;
386 }
387 ConsumeToken(); // Eat the identifier.
388 // FIXME: add Actions.BuildObjCKeyword()
389
390 keywordSelector = ParseObjCSelector();
391 if (!keywordSelector && Tok.getKind() != tok::colon)
392 break;
393 // We have a selector or a colon, continue parsing.
394 }
395 // Parse the (optional) parameter list.
396 while (Tok.getKind() == tok::comma) {
397 ConsumeToken();
398 if (Tok.getKind() == tok::ellipsis) {
399 ConsumeToken();
400 break;
401 }
402 ParseDeclaration(Declarator::PrototypeContext);
403 }
404 } else if (!selIdent) {
405 Diag(Tok, diag::err_expected_ident); // missing selector name.
406 }
407 // FIXME: add Actions.BuildMethodSignature().
Steve Naroff0bbffd82007-08-22 16:35:03 +0000408}
409
Steve Narofffb367882007-08-20 21:31:48 +0000410/// objc-protocol-refs:
411/// '<' identifier-list '>'
412///
413bool Parser::ParseObjCProtocolReferences() {
414 assert(Tok.getKind() == tok::less && "expected <");
415
416 ConsumeToken(); // the "<"
417 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
418
419 while (1) {
420 if (Tok.getKind() != tok::identifier) {
421 Diag(Tok, diag::err_expected_ident);
422 SkipUntil(tok::greater);
423 return true;
424 }
425 ProtocolRefs.push_back(Tok.getIdentifierInfo());
426 ConsumeToken();
427
428 if (Tok.getKind() != tok::comma)
429 break;
430 ConsumeToken();
431 }
432 // Consume the '>'.
433 return ExpectAndConsume(tok::greater, diag::err_expected_greater);
434}
435
436/// objc-class-instance-variables:
437/// '{' objc-instance-variable-decl-list[opt] '}'
438///
439/// objc-instance-variable-decl-list:
440/// objc-visibility-spec
441/// objc-instance-variable-decl ';'
442/// ';'
443/// objc-instance-variable-decl-list objc-visibility-spec
444/// objc-instance-variable-decl-list objc-instance-variable-decl ';'
445/// objc-instance-variable-decl-list ';'
446///
447/// objc-visibility-spec:
448/// @private
449/// @protected
450/// @public
Steve Naroffc4474992007-08-21 21:17:12 +0000451/// @package [OBJC2]
Steve Narofffb367882007-08-20 21:31:48 +0000452///
453/// objc-instance-variable-decl:
454/// struct-declaration
455///
Steve Naroffc4474992007-08-21 21:17:12 +0000456void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl) {
457 assert(Tok.getKind() == tok::l_brace && "expected {");
458
459 SourceLocation LBraceLoc = ConsumeBrace(); // the "{"
460 llvm::SmallVector<DeclTy*, 32> IvarDecls;
461
462 // While we still have something to read, read the instance variables.
463 while (Tok.getKind() != tok::r_brace &&
464 Tok.getKind() != tok::eof) {
465 // Each iteration of this loop reads one objc-instance-variable-decl.
466
467 // Check for extraneous top-level semicolon.
468 if (Tok.getKind() == tok::semi) {
469 Diag(Tok, diag::ext_extra_struct_semi);
470 ConsumeToken();
471 continue;
472 }
473 // Set the default visibility to private.
474 tok::ObjCKeywordKind visibility = tok::objc_private;
475 if (Tok.getKind() == tok::at) { // parse objc-visibility-spec
476 ConsumeToken(); // eat the @ sign
477 IdentifierInfo *specId = Tok.getIdentifierInfo();
478 switch (specId->getObjCKeywordID()) {
479 case tok::objc_private:
480 case tok::objc_public:
481 case tok::objc_protected:
482 case tok::objc_package:
483 visibility = specId->getObjCKeywordID();
484 ConsumeToken();
485 continue;
486 default:
487 Diag(Tok, diag::err_objc_illegal_visibility_spec);
488 ConsumeToken();
489 continue;
490 }
491 }
492 ParseStructDeclaration(interfaceDecl, IvarDecls);
493
494 if (Tok.getKind() == tok::semi) {
495 ConsumeToken();
496 } else if (Tok.getKind() == tok::r_brace) {
497 Diag(Tok.getLocation(), diag::ext_expected_semi_decl_list);
498 break;
499 } else {
500 Diag(Tok, diag::err_expected_semi_decl_list);
501 // Skip to end of block or statement
502 SkipUntil(tok::r_brace, true, true);
503 }
504 }
505 MatchRHSPunctuation(tok::r_brace, LBraceLoc);
506 return;
Chris Lattner4b009652007-07-25 00:24:17 +0000507}
Steve Narofffb367882007-08-20 21:31:48 +0000508
509/// objc-protocol-declaration:
510/// objc-protocol-definition
511/// objc-protocol-forward-reference
512///
513/// objc-protocol-definition:
514/// @protocol identifier
515/// objc-protocol-refs[opt]
516/// objc-methodprotolist
517/// @end
518///
519/// objc-protocol-forward-reference:
520/// @protocol identifier-list ';'
521///
522/// "@protocol identifier ;" should be resolved as "@protocol
523/// identifier-list ;": objc-methodprotolist may not start with a
524/// semicolon in the first alternative if objc-protocol-refs are omitted.
525
Steve Naroff72f17fb2007-08-22 22:17:26 +0000526Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) {
527 assert((Tok.getKind() == tok::identifier &&
528 Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_protocol) &&
529 "ParseObjCAtProtocolDeclaration(): Expected @protocol");
530 ConsumeToken(); // the "protocol" identifier
531
532 if (Tok.getKind() != tok::identifier) {
533 Diag(Tok, diag::err_expected_ident); // missing protocol name.
534 return 0;
535 }
536 // Save the protocol name, then consume it.
537 IdentifierInfo *protocolName = Tok.getIdentifierInfo();
538 SourceLocation nameLoc = ConsumeToken();
539
540 if (Tok.getKind() == tok::semi) { // forward declaration.
541 ConsumeToken();
542 return 0; // FIXME: add protocolName
543 }
544 if (Tok.getKind() == tok::comma) { // list of forward declarations.
545 // Parse the list of forward declarations.
546 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
547 ProtocolRefs.push_back(protocolName);
548
549 while (1) {
550 ConsumeToken(); // the ','
551 if (Tok.getKind() != tok::identifier) {
552 Diag(Tok, diag::err_expected_ident);
553 SkipUntil(tok::semi);
554 return 0;
555 }
556 ProtocolRefs.push_back(Tok.getIdentifierInfo());
557 ConsumeToken(); // the identifier
558
559 if (Tok.getKind() != tok::comma)
560 break;
561 }
562 // Consume the ';'.
563 if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
564 return 0;
565 return 0; // FIXME
566 }
567 // Last, and definitely not least, parse a protocol declaration.
568 if (Tok.getKind() == tok::less) {
569 if (ParseObjCProtocolReferences())
570 return 0;
571 }
572 ParseObjCInterfaceDeclList(0/*FIXME*/);
573
574 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
575 if (Tok.getKind() == tok::identifier &&
576 Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_end) {
577 ConsumeToken(); // the "end" identifier
578 return 0;
579 }
580 Diag(Tok, diag::err_objc_missing_end);
Steve Narofffb367882007-08-20 21:31:48 +0000581 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000582}
Steve Narofffb367882007-08-20 21:31:48 +0000583
584/// objc-implementation:
585/// objc-class-implementation-prologue
586/// objc-category-implementation-prologue
587///
588/// objc-class-implementation-prologue:
589/// @implementation identifier objc-superclass[opt]
590/// objc-class-instance-variables[opt]
591///
592/// objc-category-implementation-prologue:
593/// @implementation identifier ( identifier )
594
595Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000596 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000597 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000598}
Steve Narofffb367882007-08-20 21:31:48 +0000599Parser::DeclTy *Parser::ParseObjCAtEndDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000600 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000601 return 0;
602}
603Parser::DeclTy *Parser::ParseObjCAtAliasDeclaration() {
604 assert(0 && "Unimp");
605 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000606}
607
Steve Naroff72f17fb2007-08-22 22:17:26 +0000608void Parser::ParseObjCInstanceMethodDefinition() {
609 assert(0 && "Parser::ParseObjCInstanceMethodDefinition():: Unimp");
Chris Lattner4b009652007-07-25 00:24:17 +0000610}
611
Steve Naroff72f17fb2007-08-22 22:17:26 +0000612void Parser::ParseObjCClassMethodDefinition() {
613 assert(0 && "Parser::ParseObjCClassMethodDefinition():: Unimp");
Chris Lattner4b009652007-07-25 00:24:17 +0000614}
Anders Carlssona66cad42007-08-21 17:43:55 +0000615
616Parser::ExprResult Parser::ParseObjCExpression() {
617 SourceLocation AtLoc = ConsumeToken(); // the "@"
618
619 switch (Tok.getKind()) {
620 case tok::string_literal: // primary-expression: string-literal
621 case tok::wide_string_literal:
622 return ParseObjCStringLiteral();
Anders Carlsson8be1d402007-08-22 15:14:15 +0000623 case tok::objc_encode:
624 return ParseObjCEncodeExpression();
625 break;
Anders Carlssona66cad42007-08-21 17:43:55 +0000626 default:
627 Diag(AtLoc, diag::err_unexpected_at);
628 SkipUntil(tok::semi);
629 break;
630 }
631
632 return 0;
633}
634
635Parser::ExprResult Parser::ParseObjCStringLiteral() {
636 ExprResult Res = ParseStringLiteralExpression();
637
638 if (Res.isInvalid) return Res;
639
640 return Actions.ParseObjCStringLiteral(Res.Val);
641}
Anders Carlsson8be1d402007-08-22 15:14:15 +0000642
643/// objc-encode-expression:
644/// @encode ( type-name )
645Parser::ExprResult Parser::ParseObjCEncodeExpression() {
646 assert(Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_encode &&
647 "Not an @encode expression!");
648
649 SourceLocation EncLoc = ConsumeToken();
650
651 if (Tok.getKind() != tok::l_paren) {
652 Diag(Tok, diag::err_expected_lparen_after, "@encode");
653 return true;
654 }
655
656 SourceLocation LParenLoc = ConsumeParen();
657
658 TypeTy *Ty = ParseTypeName();
659
660 if (Tok.getKind() != tok::r_paren) {
661 Diag(Tok, diag::err_expected_rparen);
662 return true;
663 }
664
665 return Actions.ParseObjCEncodeExpression(EncLoc, LParenLoc, Ty,
666 ConsumeParen());
667}