blob: 94a5c8d42cb0138dab8a6f9f6ff9ed7e734ab7b3 [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.
123 IdentifierInfo *nameId = Tok.getIdentifierInfo();
124 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
150 //ParseObjCInterfaceDeclList();
151
152 if (Tok.getKind() != tok::at) { // check for @end
153 Diag(Tok, diag::err_objc_missing_end);
154 return 0;
155 }
156 SourceLocation atEndLoc = ConsumeToken(); // eat the @ sign
157 if (Tok.getIdentifierInfo()->getObjCKeywordID() != tok::objc_end) {
158 Diag(Tok, diag::err_objc_missing_end);
159 return 0;
160 }
161 ConsumeToken(); // the "end" identifier
162 return 0;
163 }
164 // Parse a class interface.
165 IdentifierInfo *superClassId = 0;
166 SourceLocation superClassLoc;
167
168 if (Tok.getKind() == tok::colon) { // a super class is specified.
169 ConsumeToken();
170 if (Tok.getKind() != tok::identifier) {
171 Diag(Tok, diag::err_expected_ident); // missing super class name.
172 return 0;
173 }
174 superClassId = Tok.getIdentifierInfo();
175 superClassLoc = ConsumeToken();
176 }
177 // Next, we need to check for any protocol references.
178 if (Tok.getKind() == tok::less) {
179 if (ParseObjCProtocolReferences())
180 return 0;
181 }
Steve Naroffc4474992007-08-21 21:17:12 +0000182 // FIXME: add Actions.StartObjCClassInterface(nameId, superClassId, ...)
Steve Narofffb367882007-08-20 21:31:48 +0000183 if (Tok.getKind() == tok::l_brace)
Steve Naroffc4474992007-08-21 21:17:12 +0000184 ParseObjCClassInstanceVariables(0/*FIXME*/);
Steve Narofffb367882007-08-20 21:31:48 +0000185
186 //ParseObjCInterfaceDeclList();
187
188 if (Tok.getKind() != tok::at) { // check for @end
189 Diag(Tok, diag::err_objc_missing_end);
190 return 0;
191 }
192 SourceLocation atEndLoc = ConsumeToken(); // eat the @ sign
193 if (Tok.getIdentifierInfo()->getObjCKeywordID() != tok::objc_end) {
194 Diag(Tok, diag::err_objc_missing_end);
195 return 0;
196 }
197 ConsumeToken(); // the "end" identifier
198 return 0;
199}
200
201/// objc-interface-decl-list:
202/// empty
203/// objc-interface-decl-list objc-method-proto
204/// objc-interface-decl-list objc-property-decl [OBJC2]
205/// objc-interface-decl-list declaration
206/// objc-interface-decl-list ';'
207///
208void Parser::ParseObjCInterfaceDeclList() {
Chris Lattner4b009652007-07-25 00:24:17 +0000209 assert(0 && "Unimp");
210}
Steve Narofffb367882007-08-20 21:31:48 +0000211
212/// objc-protocol-refs:
213/// '<' identifier-list '>'
214///
215bool Parser::ParseObjCProtocolReferences() {
216 assert(Tok.getKind() == tok::less && "expected <");
217
218 ConsumeToken(); // the "<"
219 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
220
221 while (1) {
222 if (Tok.getKind() != tok::identifier) {
223 Diag(Tok, diag::err_expected_ident);
224 SkipUntil(tok::greater);
225 return true;
226 }
227 ProtocolRefs.push_back(Tok.getIdentifierInfo());
228 ConsumeToken();
229
230 if (Tok.getKind() != tok::comma)
231 break;
232 ConsumeToken();
233 }
234 // Consume the '>'.
235 return ExpectAndConsume(tok::greater, diag::err_expected_greater);
236}
237
238/// objc-class-instance-variables:
239/// '{' objc-instance-variable-decl-list[opt] '}'
240///
241/// objc-instance-variable-decl-list:
242/// objc-visibility-spec
243/// objc-instance-variable-decl ';'
244/// ';'
245/// objc-instance-variable-decl-list objc-visibility-spec
246/// objc-instance-variable-decl-list objc-instance-variable-decl ';'
247/// objc-instance-variable-decl-list ';'
248///
249/// objc-visibility-spec:
250/// @private
251/// @protected
252/// @public
Steve Naroffc4474992007-08-21 21:17:12 +0000253/// @package [OBJC2]
Steve Narofffb367882007-08-20 21:31:48 +0000254///
255/// objc-instance-variable-decl:
256/// struct-declaration
257///
Steve Naroffc4474992007-08-21 21:17:12 +0000258void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl) {
259 assert(Tok.getKind() == tok::l_brace && "expected {");
260
261 SourceLocation LBraceLoc = ConsumeBrace(); // the "{"
262 llvm::SmallVector<DeclTy*, 32> IvarDecls;
263
264 // While we still have something to read, read the instance variables.
265 while (Tok.getKind() != tok::r_brace &&
266 Tok.getKind() != tok::eof) {
267 // Each iteration of this loop reads one objc-instance-variable-decl.
268
269 // Check for extraneous top-level semicolon.
270 if (Tok.getKind() == tok::semi) {
271 Diag(Tok, diag::ext_extra_struct_semi);
272 ConsumeToken();
273 continue;
274 }
275 // Set the default visibility to private.
276 tok::ObjCKeywordKind visibility = tok::objc_private;
277 if (Tok.getKind() == tok::at) { // parse objc-visibility-spec
278 ConsumeToken(); // eat the @ sign
279 IdentifierInfo *specId = Tok.getIdentifierInfo();
280 switch (specId->getObjCKeywordID()) {
281 case tok::objc_private:
282 case tok::objc_public:
283 case tok::objc_protected:
284 case tok::objc_package:
285 visibility = specId->getObjCKeywordID();
286 ConsumeToken();
287 continue;
288 default:
289 Diag(Tok, diag::err_objc_illegal_visibility_spec);
290 ConsumeToken();
291 continue;
292 }
293 }
294 ParseStructDeclaration(interfaceDecl, IvarDecls);
295
296 if (Tok.getKind() == tok::semi) {
297 ConsumeToken();
298 } else if (Tok.getKind() == tok::r_brace) {
299 Diag(Tok.getLocation(), diag::ext_expected_semi_decl_list);
300 break;
301 } else {
302 Diag(Tok, diag::err_expected_semi_decl_list);
303 // Skip to end of block or statement
304 SkipUntil(tok::r_brace, true, true);
305 }
306 }
307 MatchRHSPunctuation(tok::r_brace, LBraceLoc);
308 return;
Chris Lattner4b009652007-07-25 00:24:17 +0000309}
Steve Narofffb367882007-08-20 21:31:48 +0000310
311/// objc-protocol-declaration:
312/// objc-protocol-definition
313/// objc-protocol-forward-reference
314///
315/// objc-protocol-definition:
316/// @protocol identifier
317/// objc-protocol-refs[opt]
318/// objc-methodprotolist
319/// @end
320///
321/// objc-protocol-forward-reference:
322/// @protocol identifier-list ';'
323///
324/// "@protocol identifier ;" should be resolved as "@protocol
325/// identifier-list ;": objc-methodprotolist may not start with a
326/// semicolon in the first alternative if objc-protocol-refs are omitted.
327
328Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000329 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000330 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000331}
Steve Narofffb367882007-08-20 21:31:48 +0000332
333/// objc-implementation:
334/// objc-class-implementation-prologue
335/// objc-category-implementation-prologue
336///
337/// objc-class-implementation-prologue:
338/// @implementation identifier objc-superclass[opt]
339/// objc-class-instance-variables[opt]
340///
341/// objc-category-implementation-prologue:
342/// @implementation identifier ( identifier )
343
344Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000345 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000346 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000347}
Steve Narofffb367882007-08-20 21:31:48 +0000348Parser::DeclTy *Parser::ParseObjCAtEndDeclaration() {
Chris Lattner4b009652007-07-25 00:24:17 +0000349 assert(0 && "Unimp");
Steve Narofffb367882007-08-20 21:31:48 +0000350 return 0;
351}
352Parser::DeclTy *Parser::ParseObjCAtAliasDeclaration() {
353 assert(0 && "Unimp");
354 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000355}
356
357void Parser::ParseObjCInstanceMethodDeclaration() {
358 assert(0 && "Unimp");
359}
360
361void Parser::ParseObjCClassMethodDeclaration() {
362 assert(0 && "Unimp");
363}
Anders Carlssona66cad42007-08-21 17:43:55 +0000364
365Parser::ExprResult Parser::ParseObjCExpression() {
366 SourceLocation AtLoc = ConsumeToken(); // the "@"
367
368 switch (Tok.getKind()) {
369 case tok::string_literal: // primary-expression: string-literal
370 case tok::wide_string_literal:
371 return ParseObjCStringLiteral();
372 default:
373 Diag(AtLoc, diag::err_unexpected_at);
374 SkipUntil(tok::semi);
375 break;
376 }
377
378 return 0;
379}
380
381Parser::ExprResult Parser::ParseObjCStringLiteral() {
382 ExprResult Res = ParseStringLiteralExpression();
383
384 if (Res.isInvalid) return Res;
385
386 return Actions.ParseObjCStringLiteral(Res.Val);
387}