blob: 2eef86745ed21b862075573854f6d19f8bfe2e7d [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"
15#include "clang/Basic/Diagnostic.h"
16#include "llvm/ADT/SmallVector.h"
17using namespace clang;
18
19
20/// ParseExternalDeclaration:
21/// external-declaration: [C99 6.9]
22/// [OBJC] objc-class-definition
23/// [OBJC] objc-class-declaration [TODO]
24/// [OBJC] objc-alias-declaration [TODO]
25/// [OBJC] objc-protocol-definition [TODO]
26/// [OBJC] objc-method-definition [TODO]
27/// [OBJC] '@' 'end' [TODO]
Steve Narofffb367882007-08-20 21:31:48 +000028Parser::DeclTy *Parser::ParseObjCAtDirectives() {
Chris Lattner4b009652007-07-25 00:24:17 +000029 SourceLocation AtLoc = ConsumeToken(); // the "@"
30
31 IdentifierInfo *II = Tok.getIdentifierInfo();
32 switch (II ? II->getObjCKeywordID() : tok::objc_not_keyword) {
33 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:
38 return ParseObjCAtProtocolDeclaration();
39 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 }
66
67 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) {
114 assert(Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_interface &&
115 "ParseObjCAtInterfaceDeclaration(): Expected @interface");
116 ConsumeToken(); // the "interface" identifier
117
118 if (Tok.getKind() != tok::identifier) {
119 Diag(Tok, diag::err_expected_ident); // missing class or category name.
120 return 0;
121 }
122 // We have a class or category name - consume it.
Steve Naroff0bbffd82007-08-22 16:35:03 +0000123 // IdentifierInfo *nameId = Tok.getIdentifierInfo();
Steve Narofffb367882007-08-20 21:31:48 +0000124 SourceLocation nameLoc = ConsumeToken();
125
126 if (Tok.getKind() == tok::l_paren) { // we have a category
127 SourceLocation lparenLoc = ConsumeParen();
128 SourceLocation categoryLoc, rparenLoc;
129 IdentifierInfo *categoryId = 0;
130
131 // OBJC2: The cateogry name is optional (not an error).
132 if (Tok.getKind() == tok::identifier) {
133 categoryId = Tok.getIdentifierInfo();
134 categoryLoc = ConsumeToken();
135 }
136 if (Tok.getKind() != tok::r_paren) {
137 Diag(Tok, diag::err_expected_rparen);
138 SkipUntil(tok::r_paren, false); // don't stop at ';'
139 return 0;
140 }
141 rparenLoc = ConsumeParen();
142 // Next, we need to check for any protocol references.
143 if (Tok.getKind() == tok::less) {
144 if (ParseObjCProtocolReferences())
145 return 0;
146 }
147 if (attrList) // categories don't support attributes.
148 Diag(Tok, diag::err_objc_no_attributes_on_category);
149
Steve Naroff0bbffd82007-08-22 16:35:03 +0000150 ParseObjCInterfaceDeclList(0/*FIXME*/);
Steve Narofffb367882007-08-20 21:31:48 +0000151
Steve Naroff0bbffd82007-08-22 16:35:03 +0000152 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
153 if (Tok.getKind() == tok::identifier &&
154 Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_end) {
155 ConsumeToken(); // the "end" identifier
Steve Narofffb367882007-08-20 21:31:48 +0000156 return 0;
157 }
Steve Naroff0bbffd82007-08-22 16:35:03 +0000158 Diag(Tok, diag::err_objc_missing_end);
Steve Narofffb367882007-08-20 21:31:48 +0000159 return 0;
160 }
161 // Parse a class interface.
162 IdentifierInfo *superClassId = 0;
163 SourceLocation superClassLoc;
164
165 if (Tok.getKind() == tok::colon) { // a super class is specified.
166 ConsumeToken();
167 if (Tok.getKind() != tok::identifier) {
168 Diag(Tok, diag::err_expected_ident); // missing super class name.
169 return 0;
170 }
171 superClassId = Tok.getIdentifierInfo();
172 superClassLoc = ConsumeToken();
173 }
174 // Next, we need to check for any protocol references.
175 if (Tok.getKind() == tok::less) {
176 if (ParseObjCProtocolReferences())
177 return 0;
178 }
Steve Naroffc4474992007-08-21 21:17:12 +0000179 // FIXME: add Actions.StartObjCClassInterface(nameId, superClassId, ...)
Steve Narofffb367882007-08-20 21:31:48 +0000180 if (Tok.getKind() == tok::l_brace)
Steve Naroffc4474992007-08-21 21:17:12 +0000181 ParseObjCClassInstanceVariables(0/*FIXME*/);
Steve Narofffb367882007-08-20 21:31:48 +0000182
Steve Naroff0bbffd82007-08-22 16:35:03 +0000183 ParseObjCInterfaceDeclList(0/*FIXME*/);
184
185 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
186 if (Tok.getKind() == tok::identifier &&
187 Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_end) {
188 ConsumeToken(); // the "end" identifier
Steve Narofffb367882007-08-20 21:31:48 +0000189 return 0;
190 }
Steve Naroff0bbffd82007-08-22 16:35:03 +0000191 Diag(Tok, diag::err_objc_missing_end);
Steve Narofffb367882007-08-20 21:31:48 +0000192 return 0;
193}
194
195/// objc-interface-decl-list:
196/// empty
Steve Narofffb367882007-08-20 21:31:48 +0000197/// objc-interface-decl-list objc-property-decl [OBJC2]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000198/// objc-interface-decl-list objc-method-requirement [OBJC2]
199/// objc-interface-decl-list objc-method-proto
Steve Narofffb367882007-08-20 21:31:48 +0000200/// objc-interface-decl-list declaration
201/// objc-interface-decl-list ';'
202///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000203/// objc-method-requirement: [OBJC2]
204/// @required
205/// @optional
206///
207void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl) {
208 while (1) {
209 if (Tok.getKind() == tok::at) {
210 SourceLocation AtLoc = ConsumeToken(); // the "@"
211 tok::ObjCKeywordKind ocKind = Tok.getIdentifierInfo()->getObjCKeywordID();
212
213 if (ocKind == tok::objc_end) { // terminate list
214 return;
215 } else if (ocKind == tok::objc_required) { // protocols only
216 ConsumeToken();
217 continue;
218 } else if (ocKind == tok::objc_optional) { // protocols only
219 ConsumeToken();
220 continue;
221 } else if (ocKind == tok::objc_property) {
222 ParseObjCPropertyDecl(AtLoc);
223 continue;
224 } else {
225 Diag(Tok, diag::err_objc_illegal_interface_qual);
226 ConsumeToken();
227 }
228 }
229 if (Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) {
230 ParseObjCMethodPrototype();
231 continue;
232 }
233 if (Tok.getKind() == tok::semi)
234 ConsumeToken();
235 else if (Tok.getKind() == tok::eof)
236 return;
237 else
238 ParseDeclarationOrFunctionDefinition();
239 }
240}
241
242void Parser::ParseObjCPropertyDecl(SourceLocation atLoc) {
Chris Lattner4b009652007-07-25 00:24:17 +0000243 assert(0 && "Unimp");
244}
Steve Narofffb367882007-08-20 21:31:48 +0000245
Steve Naroff0bbffd82007-08-22 16:35:03 +0000246/// objc-methodproto:
247/// objc-instance-method objc-method-decl ';'
248/// objc-class-method objc-method-decl ';'
249///
250/// objc-instance-method: '-'
251/// objc-class-method: '+'
252///
253void Parser::ParseObjCMethodPrototype() {
254 assert((Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) &&
255 "expected +/-");
256
257 tok::TokenKind methodType = Tok.getKind();
258 SourceLocation methodLoc = ConsumeToken();
259
260 // FIXME: deal with "context sensitive" protocol qualifiers in prototypes
261 ParseObjCMethodDecl(methodType, methodLoc);
262
263 // Consume the ';'.
264 ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "method proto");
265}
266
267/// objc-selector:
268/// identifier
269/// one of
270/// enum struct union if else while do for switch case default
271/// break continue return goto asm sizeof typeof __alignof
272/// unsigned long const short volatile signed restrict _Complex
273/// in out inout bycopy byref oneway int char float double void _Bool
274///
275IdentifierInfo *Parser::ParseObjCSelector() {
276 tok::TokenKind tKind = Tok.getKind();
277 IdentifierInfo *II = 0;
278
279 if (tKind == tok::identifier ||
280 (tKind >= tok::kw_auto && tKind <= tok::kw__Complex)) {
281 // FIXME: make sure the list of keywords jives with gcc. For example,
282 // the above test does not include in/out/inout/bycopy/byref/oneway.
283 II = Tok.getIdentifierInfo();
284 ConsumeToken();
285 }
286 return II;
287}
288
289/// objc-type-name:
290/// '(' objc-type-qualifiers[opt] type-name ')'
291/// '(' objc-type-qualifiers[opt] ')'
292///
293/// objc-type-qualifiers:
294/// objc-type-qualifier
295/// objc-type-qualifiers objc-type-qualifier
296///
297/// objc-type-qualifier: one of
298/// in out inout bycopy byref oneway
299///
300void Parser::ParseObjCTypeName() {
301 assert(Tok.getKind() == tok::l_paren && "expected (");
302
303 SourceLocation LParenLoc = ConsumeParen(), RParenLoc;
304
305 if (isTypeSpecifierQualifier()) {
306 TypeTy *Ty = ParseTypeName();
307
308 assert(Ty && "Parser::ParseObjCTypeName(): missing type");
309 }
310 if (Tok.getKind() != tok::r_paren) {
311 MatchRHSPunctuation(tok::r_paren, LParenLoc);
312 return;
313 }
314 RParenLoc = ConsumeParen();
315}
316
317/// objc-method-decl:
318/// objc-selector
319/// objc-keyword-selector objc-optparmlist
320/// objc-type-name objc-selector
321/// objc-type-name objc-keyword-selector objc-optparmlist
322///
323/// objc-keyword-selector:
324/// objc-keyword-decl
325/// objc-keyword-selector objc-keyword-decl
326///
327/// objc-keyword-decl:
328/// objc-selector ':' objc-type-name identifier
329/// objc-selector ':' identifier
330/// ':' objc-type-name identifier
331/// ':' identifier
332///
333/// objc-optparmlist:
334/// objc-optparms objc-optellipsis
335///
336/// objc-optparms:
337/// empty
338/// objc-opt-parms , parameter-declaration
339///
340/// objc-optellipsis:
341/// empty
342/// , ...
343///
344void Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc) {
345 if (Tok.getKind() == tok::l_paren)
346 ParseObjCTypeName();
347 ParseObjCSelector();
348}
349
Steve Narofffb367882007-08-20 21:31:48 +0000350/// objc-protocol-refs:
351/// '<' identifier-list '>'
352///
353bool Parser::ParseObjCProtocolReferences() {
354 assert(Tok.getKind() == tok::less && "expected <");
355
356 ConsumeToken(); // the "<"
357 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
358
359 while (1) {
360 if (Tok.getKind() != tok::identifier) {
361 Diag(Tok, diag::err_expected_ident);
362 SkipUntil(tok::greater);
363 return true;
364 }
365 ProtocolRefs.push_back(Tok.getIdentifierInfo());
366 ConsumeToken();
367
368 if (Tok.getKind() != tok::comma)
369 break;
370 ConsumeToken();
371 }
372 // Consume the '>'.
373 return ExpectAndConsume(tok::greater, diag::err_expected_greater);
374}
375
376/// objc-class-instance-variables:
377/// '{' objc-instance-variable-decl-list[opt] '}'
378///
379/// objc-instance-variable-decl-list:
380/// objc-visibility-spec
381/// objc-instance-variable-decl ';'
382/// ';'
383/// objc-instance-variable-decl-list objc-visibility-spec
384/// objc-instance-variable-decl-list objc-instance-variable-decl ';'
385/// objc-instance-variable-decl-list ';'
386///
387/// objc-visibility-spec:
388/// @private
389/// @protected
390/// @public
Steve Naroffc4474992007-08-21 21:17:12 +0000391/// @package [OBJC2]
Steve Narofffb367882007-08-20 21:31:48 +0000392///
393/// objc-instance-variable-decl:
394/// struct-declaration
395///
Steve Naroffc4474992007-08-21 21:17:12 +0000396void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl) {
397 assert(Tok.getKind() == tok::l_brace && "expected {");
398
399 SourceLocation LBraceLoc = ConsumeBrace(); // the "{"
400 llvm::SmallVector<DeclTy*, 32> IvarDecls;
401
402 // While we still have something to read, read the instance variables.
403 while (Tok.getKind() != tok::r_brace &&
404 Tok.getKind() != tok::eof) {
405 // Each iteration of this loop reads one objc-instance-variable-decl.
406
407 // Check for extraneous top-level semicolon.
408 if (Tok.getKind() == tok::semi) {
409 Diag(Tok, diag::ext_extra_struct_semi);
410 ConsumeToken();
411 continue;
412 }
413 // Set the default visibility to private.
414 tok::ObjCKeywordKind visibility = tok::objc_private;
415 if (Tok.getKind() == tok::at) { // parse objc-visibility-spec
416 ConsumeToken(); // eat the @ sign
417 IdentifierInfo *specId = Tok.getIdentifierInfo();
418 switch (specId->getObjCKeywordID()) {
419 case tok::objc_private:
420 case tok::objc_public:
421 case tok::objc_protected:
422 case tok::objc_package:
423 visibility = specId->getObjCKeywordID();
424 ConsumeToken();
425 continue;
426 default:
427 Diag(Tok, diag::err_objc_illegal_visibility_spec);
428 ConsumeToken();
429 continue;
430 }
431 }
432 ParseStructDeclaration(interfaceDecl, IvarDecls);
433
434 if (Tok.getKind() == tok::semi) {
435 ConsumeToken();
436 } else if (Tok.getKind() == tok::r_brace) {
437 Diag(Tok.getLocation(), diag::ext_expected_semi_decl_list);
438 break;
439 } else {
440 Diag(Tok, diag::err_expected_semi_decl_list);
441 // Skip to end of block or statement
442 SkipUntil(tok::r_brace, true, true);
443 }
444 }
445 MatchRHSPunctuation(tok::r_brace, LBraceLoc);
446 return;
Chris Lattner4b009652007-07-25 00:24:17 +0000447}
Steve Narofffb367882007-08-20 21:31:48 +0000448
449/// objc-protocol-declaration:
450/// objc-protocol-definition
451/// objc-protocol-forward-reference
452///
453/// objc-protocol-definition:
454/// @protocol identifier
455/// objc-protocol-refs[opt]
456/// objc-methodprotolist
457/// @end
458///
459/// objc-protocol-forward-reference:
460/// @protocol identifier-list ';'
461///
462/// "@protocol identifier ;" should be resolved as "@protocol
463/// identifier-list ;": objc-methodprotolist may not start with a
464/// semicolon in the first alternative if objc-protocol-refs are omitted.
465
466Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000467 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000468 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000469}
Steve Narofffb367882007-08-20 21:31:48 +0000470
471/// objc-implementation:
472/// objc-class-implementation-prologue
473/// objc-category-implementation-prologue
474///
475/// objc-class-implementation-prologue:
476/// @implementation identifier objc-superclass[opt]
477/// objc-class-instance-variables[opt]
478///
479/// objc-category-implementation-prologue:
480/// @implementation identifier ( identifier )
481
482Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000483 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000484 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000485}
Steve Narofffb367882007-08-20 21:31:48 +0000486Parser::DeclTy *Parser::ParseObjCAtEndDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000487 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000488 return 0;
489}
490Parser::DeclTy *Parser::ParseObjCAtAliasDeclaration() {
491 assert(0 && "Unimp");
492 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000493}
494
495void Parser::ParseObjCInstanceMethodDeclaration() {
496 assert(0 && "Unimp");
497}
498
499void Parser::ParseObjCClassMethodDeclaration() {
500 assert(0 && "Unimp");
501}
Anders Carlssona66cad42007-08-21 17:43:55 +0000502
503Parser::ExprResult Parser::ParseObjCExpression() {
504 SourceLocation AtLoc = ConsumeToken(); // the "@"
505
506 switch (Tok.getKind()) {
507 case tok::string_literal: // primary-expression: string-literal
508 case tok::wide_string_literal:
509 return ParseObjCStringLiteral();
Anders Carlsson8be1d402007-08-22 15:14:15 +0000510 case tok::objc_encode:
511 return ParseObjCEncodeExpression();
512 break;
Anders Carlssona66cad42007-08-21 17:43:55 +0000513 default:
514 Diag(AtLoc, diag::err_unexpected_at);
515 SkipUntil(tok::semi);
516 break;
517 }
518
519 return 0;
520}
521
522Parser::ExprResult Parser::ParseObjCStringLiteral() {
523 ExprResult Res = ParseStringLiteralExpression();
524
525 if (Res.isInvalid) return Res;
526
527 return Actions.ParseObjCStringLiteral(Res.Val);
528}
Anders Carlsson8be1d402007-08-22 15:14:15 +0000529
530/// objc-encode-expression:
531/// @encode ( type-name )
532Parser::ExprResult Parser::ParseObjCEncodeExpression() {
533 assert(Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_encode &&
534 "Not an @encode expression!");
535
536 SourceLocation EncLoc = ConsumeToken();
537
538 if (Tok.getKind() != tok::l_paren) {
539 Diag(Tok, diag::err_expected_lparen_after, "@encode");
540 return true;
541 }
542
543 SourceLocation LParenLoc = ConsumeParen();
544
545 TypeTy *Ty = ParseTypeName();
546
547 if (Tok.getKind() != tok::r_paren) {
548 Diag(Tok, diag::err_expected_rparen);
549 return true;
550 }
551
552 return Actions.ParseObjCEncodeExpression(EncLoc, LParenLoc, Ty,
553 ConsumeParen());
554}