blob: eaf198fc92960c405c09fb12750898d0da36e320 [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:
Steve Naroff81f1bba2007-09-06 21:24:23 +000040 return ObjcImpDecl = ParseObjCAtImplementationDeclaration(AtLoc);
Chris Lattner4b009652007-07-25 00:24:17 +000041 case tok::objc_end:
Fariborz Jahanian027c23b2007-09-01 00:26:16 +000042 return ParseObjCAtEndDeclaration(AtLoc);
Chris Lattner4b009652007-07-25 00:24:17 +000043 case tok::objc_compatibility_alias:
Fariborz Jahanianb62aff32007-09-04 19:26:51 +000044 return ParseObjCAtAliasDeclaration(AtLoc);
Fariborz Jahanian027c23b2007-09-01 00:26:16 +000045 case tok::objc_synthesize:
46 return ParseObjCPropertySynthesize(AtLoc);
47 case tok::objc_dynamic:
48 return ParseObjCPropertyDynamic(AtLoc);
Chris Lattner4b009652007-07-25 00:24:17 +000049 default:
50 Diag(AtLoc, diag::err_unexpected_at);
51 SkipUntil(tok::semi);
Steve Narofffb367882007-08-20 21:31:48 +000052 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +000053 }
54}
55
56///
57/// objc-class-declaration:
58/// '@' 'class' identifier-list ';'
59///
Steve Narofffb367882007-08-20 21:31:48 +000060Parser::DeclTy *Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
Chris Lattner4b009652007-07-25 00:24:17 +000061 ConsumeToken(); // the identifier "class"
62 llvm::SmallVector<IdentifierInfo *, 8> ClassNames;
63
64 while (1) {
65 if (Tok.getKind() != tok::identifier) {
66 Diag(Tok, diag::err_expected_ident);
67 SkipUntil(tok::semi);
Steve Narofffb367882007-08-20 21:31:48 +000068 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +000069 }
Chris Lattner4b009652007-07-25 00:24:17 +000070 ClassNames.push_back(Tok.getIdentifierInfo());
71 ConsumeToken();
72
73 if (Tok.getKind() != tok::comma)
74 break;
75
76 ConsumeToken();
77 }
78
79 // Consume the ';'.
80 if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
Steve Narofffb367882007-08-20 21:31:48 +000081 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +000082
Steve Naroffb4dfe362007-10-02 22:39:18 +000083 return Actions.ActOnForwardClassDeclaration(CurScope, atLoc,
Steve Naroff81f1bba2007-09-06 21:24:23 +000084 &ClassNames[0], ClassNames.size());
Chris Lattner4b009652007-07-25 00:24:17 +000085}
86
Steve Narofffb367882007-08-20 21:31:48 +000087///
88/// objc-interface:
89/// objc-class-interface-attributes[opt] objc-class-interface
90/// objc-category-interface
91///
92/// objc-class-interface:
93/// '@' 'interface' identifier objc-superclass[opt]
94/// objc-protocol-refs[opt]
95/// objc-class-instance-variables[opt]
96/// objc-interface-decl-list
97/// @end
98///
99/// objc-category-interface:
100/// '@' 'interface' identifier '(' identifier[opt] ')'
101/// objc-protocol-refs[opt]
102/// objc-interface-decl-list
103/// @end
104///
105/// objc-superclass:
106/// ':' identifier
107///
108/// objc-class-interface-attributes:
109/// __attribute__((visibility("default")))
110/// __attribute__((visibility("hidden")))
111/// __attribute__((deprecated))
112/// __attribute__((unavailable))
113/// __attribute__((objc_exception)) - used by NSException on 64-bit
114///
115Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration(
116 SourceLocation atLoc, AttributeList *attrList) {
Steve Naroff87c329f2007-08-23 18:16:40 +0000117 assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
Steve Narofffb367882007-08-20 21:31:48 +0000118 "ParseObjCAtInterfaceDeclaration(): Expected @interface");
119 ConsumeToken(); // the "interface" identifier
120
121 if (Tok.getKind() != tok::identifier) {
122 Diag(Tok, diag::err_expected_ident); // missing class or category name.
123 return 0;
124 }
125 // We have a class or category name - consume it.
Steve Naroff72f17fb2007-08-22 22:17:26 +0000126 IdentifierInfo *nameId = Tok.getIdentifierInfo();
Steve Narofffb367882007-08-20 21:31:48 +0000127 SourceLocation nameLoc = ConsumeToken();
128
Steve Naroffa7f62782007-08-23 19:56:30 +0000129 if (Tok.getKind() == tok::l_paren) { // we have a category.
Steve Narofffb367882007-08-20 21:31:48 +0000130 SourceLocation lparenLoc = ConsumeParen();
131 SourceLocation categoryLoc, rparenLoc;
132 IdentifierInfo *categoryId = 0;
Fariborz Jahanianf25220e2007-09-18 20:26:58 +0000133 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
Steve Narofffb367882007-08-20 21:31:48 +0000134
Steve Naroffa7f62782007-08-23 19:56:30 +0000135 // For ObjC2, the category name is optional (not an error).
Steve Narofffb367882007-08-20 21:31:48 +0000136 if (Tok.getKind() == tok::identifier) {
137 categoryId = Tok.getIdentifierInfo();
138 categoryLoc = ConsumeToken();
Steve Naroffa7f62782007-08-23 19:56:30 +0000139 } else if (!getLang().ObjC2) {
140 Diag(Tok, diag::err_expected_ident); // missing category name.
141 return 0;
Steve Narofffb367882007-08-20 21:31:48 +0000142 }
143 if (Tok.getKind() != tok::r_paren) {
144 Diag(Tok, diag::err_expected_rparen);
145 SkipUntil(tok::r_paren, false); // don't stop at ';'
146 return 0;
147 }
148 rparenLoc = ConsumeParen();
149 // Next, we need to check for any protocol references.
150 if (Tok.getKind() == tok::less) {
Steve Naroff304ed392007-09-05 23:30:30 +0000151 if (ParseObjCProtocolReferences(ProtocolRefs))
Steve Narofffb367882007-08-20 21:31:48 +0000152 return 0;
153 }
154 if (attrList) // categories don't support attributes.
155 Diag(Tok, diag::err_objc_no_attributes_on_category);
156
Fariborz Jahanian0c5affb2007-09-29 00:54:24 +0000157 DeclTy *CategoryType = Actions.ObjcStartCatInterface(CurScope, atLoc,
Fariborz Jahanianf25220e2007-09-18 20:26:58 +0000158 nameId, nameLoc,
159 categoryId, categoryLoc,
160 &ProtocolRefs[0],
161 ProtocolRefs.size());
162
163 ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword);
Steve Narofffb367882007-08-20 21:31:48 +0000164
Steve Naroff0bbffd82007-08-22 16:35:03 +0000165 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
Steve Naroff87c329f2007-08-23 18:16:40 +0000166 if (Tok.isObjCAtKeyword(tok::objc_end)) {
Steve Naroff0bbffd82007-08-22 16:35:03 +0000167 ConsumeToken(); // the "end" identifier
Steve Narofffb367882007-08-20 21:31:48 +0000168 return 0;
169 }
Steve Naroff0bbffd82007-08-22 16:35:03 +0000170 Diag(Tok, diag::err_objc_missing_end);
Steve Narofffb367882007-08-20 21:31:48 +0000171 return 0;
172 }
173 // Parse a class interface.
174 IdentifierInfo *superClassId = 0;
175 SourceLocation superClassLoc;
Steve Naroff72f17fb2007-08-22 22:17:26 +0000176
Steve Narofffb367882007-08-20 21:31:48 +0000177 if (Tok.getKind() == tok::colon) { // a super class is specified.
178 ConsumeToken();
179 if (Tok.getKind() != tok::identifier) {
180 Diag(Tok, diag::err_expected_ident); // missing super class name.
181 return 0;
182 }
183 superClassId = Tok.getIdentifierInfo();
184 superClassLoc = ConsumeToken();
185 }
186 // Next, we need to check for any protocol references.
Steve Naroff304ed392007-09-05 23:30:30 +0000187 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
Steve Narofffb367882007-08-20 21:31:48 +0000188 if (Tok.getKind() == tok::less) {
Steve Naroff304ed392007-09-05 23:30:30 +0000189 if (ParseObjCProtocolReferences(ProtocolRefs))
Steve Narofffb367882007-08-20 21:31:48 +0000190 return 0;
191 }
Fariborz Jahanianc091b5d2007-09-25 18:38:09 +0000192 DeclTy *ClsType = Actions.ObjcStartClassInterface(CurScope,
193 atLoc, nameId, nameLoc,
Steve Naroff304ed392007-09-05 23:30:30 +0000194 superClassId, superClassLoc, &ProtocolRefs[0],
195 ProtocolRefs.size(), attrList);
196
Steve Narofffb367882007-08-20 21:31:48 +0000197 if (Tok.getKind() == tok::l_brace)
Steve Naroff81f1bba2007-09-06 21:24:23 +0000198 ParseObjCClassInstanceVariables(ClsType);
Steve Narofffb367882007-08-20 21:31:48 +0000199
Fariborz Jahanian63ca8ae2007-09-17 21:07:36 +0000200 ParseObjCInterfaceDeclList(ClsType, tok::objc_interface);
Steve Naroff0bbffd82007-08-22 16:35:03 +0000201
202 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
Steve Naroff87c329f2007-08-23 18:16:40 +0000203 if (Tok.isObjCAtKeyword(tok::objc_end)) {
Steve Naroff0bbffd82007-08-22 16:35:03 +0000204 ConsumeToken(); // the "end" identifier
Steve Narofffaed3bf2007-09-10 20:51:04 +0000205 return ClsType;
Steve Narofffb367882007-08-20 21:31:48 +0000206 }
Steve Naroff0bbffd82007-08-22 16:35:03 +0000207 Diag(Tok, diag::err_objc_missing_end);
Steve Narofffb367882007-08-20 21:31:48 +0000208 return 0;
209}
210
211/// objc-interface-decl-list:
212/// empty
Steve Narofffb367882007-08-20 21:31:48 +0000213/// objc-interface-decl-list objc-property-decl [OBJC2]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000214/// objc-interface-decl-list objc-method-requirement [OBJC2]
Steve Naroff81f1bba2007-09-06 21:24:23 +0000215/// objc-interface-decl-list objc-method-proto ';'
Steve Narofffb367882007-08-20 21:31:48 +0000216/// objc-interface-decl-list declaration
217/// objc-interface-decl-list ';'
218///
Steve Naroff0bbffd82007-08-22 16:35:03 +0000219/// objc-method-requirement: [OBJC2]
220/// @required
221/// @optional
222///
Fariborz Jahanian63ca8ae2007-09-17 21:07:36 +0000223void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl,
224 tok::ObjCKeywordKind contextKey) {
Fariborz Jahanian3dc7cbc2007-09-10 20:33:04 +0000225 llvm::SmallVector<DeclTy*, 32> allMethods;
Fariborz Jahanian8b5ab6f2007-09-18 00:25:23 +0000226 tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
Steve Naroff0bbffd82007-08-22 16:35:03 +0000227 while (1) {
228 if (Tok.getKind() == tok::at) {
229 SourceLocation AtLoc = ConsumeToken(); // the "@"
Steve Naroff87c329f2007-08-23 18:16:40 +0000230 tok::ObjCKeywordKind ocKind = Tok.getObjCKeywordID();
Steve Naroff0bbffd82007-08-22 16:35:03 +0000231
232 if (ocKind == tok::objc_end) { // terminate list
Fariborz Jahanian3dc7cbc2007-09-10 20:33:04 +0000233 break;
Steve Naroff0bbffd82007-08-22 16:35:03 +0000234 } else if (ocKind == tok::objc_required) { // protocols only
235 ConsumeToken();
Fariborz Jahanian8b5ab6f2007-09-18 00:25:23 +0000236 MethodImplKind = ocKind;
Fariborz Jahanian63ca8ae2007-09-17 21:07:36 +0000237 if (contextKey != tok::objc_protocol)
238 Diag(AtLoc, diag::err_objc_protocol_required);
Steve Naroff0bbffd82007-08-22 16:35:03 +0000239 } else if (ocKind == tok::objc_optional) { // protocols only
240 ConsumeToken();
Fariborz Jahanian8b5ab6f2007-09-18 00:25:23 +0000241 MethodImplKind = ocKind;
Fariborz Jahanian63ca8ae2007-09-17 21:07:36 +0000242 if (contextKey != tok::objc_protocol)
243 Diag(AtLoc, diag::err_objc_protocol_optional);
Steve Naroff0bbffd82007-08-22 16:35:03 +0000244 } else if (ocKind == tok::objc_property) {
Fariborz Jahanian86f74a42007-09-12 18:23:47 +0000245 ParseObjCPropertyDecl(interfaceDecl);
Steve Naroff0bbffd82007-08-22 16:35:03 +0000246 continue;
247 } else {
248 Diag(Tok, diag::err_objc_illegal_interface_qual);
249 ConsumeToken();
250 }
251 }
252 if (Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) {
Fariborz Jahanian8b5ab6f2007-09-18 00:25:23 +0000253 DeclTy *methodPrototype = ParseObjCMethodPrototype(interfaceDecl, MethodImplKind);
Fariborz Jahanian63ca8ae2007-09-17 21:07:36 +0000254 allMethods.push_back(methodPrototype);
Steve Naroff81f1bba2007-09-06 21:24:23 +0000255 // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
256 // method definitions.
Steve Naroffaa1b6d42007-09-17 15:07:43 +0000257 ExpectAndConsume(tok::semi, diag::err_expected_semi_after,"method proto");
Steve Naroff0bbffd82007-08-22 16:35:03 +0000258 continue;
259 }
260 if (Tok.getKind() == tok::semi)
261 ConsumeToken();
262 else if (Tok.getKind() == tok::eof)
Fariborz Jahanian3dc7cbc2007-09-10 20:33:04 +0000263 break;
Steve Naroff304ed392007-09-05 23:30:30 +0000264 else {
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000265 // FIXME: as the name implies, this rule allows function definitions.
266 // We could pass a flag or check for functions during semantic analysis.
Steve Naroff81f1bba2007-09-06 21:24:23 +0000267 ParseDeclarationOrFunctionDefinition();
Steve Naroff304ed392007-09-05 23:30:30 +0000268 }
Steve Naroff0bbffd82007-08-22 16:35:03 +0000269 }
Fariborz Jahanian3dc7cbc2007-09-10 20:33:04 +0000270 /// Insert collected methods declarations into the @interface object.
Fariborz Jahanian0c5affb2007-09-29 00:54:24 +0000271 Actions.ObjcAddMethodsToClass(CurScope,
272 interfaceDecl,&allMethods[0],allMethods.size());
Steve Naroff0bbffd82007-08-22 16:35:03 +0000273}
274
Fariborz Jahanian6668b8c2007-08-31 16:11:31 +0000275/// Parse property attribute declarations.
276///
277/// property-attr-decl: '(' property-attrlist ')'
278/// property-attrlist:
279/// property-attribute
280/// property-attrlist ',' property-attribute
281/// property-attribute:
282/// getter '=' identifier
283/// setter '=' identifier ':'
284/// readonly
285/// readwrite
286/// assign
287/// retain
288/// copy
289/// nonatomic
290///
291void Parser::ParseObjCPropertyAttribute (DeclTy *interfaceDecl) {
292 SourceLocation loc = ConsumeParen(); // consume '('
293 while (isObjCPropertyAttribute()) {
294 const IdentifierInfo *II = Tok.getIdentifierInfo();
295 // getter/setter require extra treatment.
296 if (II == ObjcPropertyAttrs[objc_getter] ||
297 II == ObjcPropertyAttrs[objc_setter]) {
298 // skip getter/setter part.
299 SourceLocation loc = ConsumeToken();
300 if (Tok.getKind() == tok::equal) {
301 loc = ConsumeToken();
302 if (Tok.getKind() == tok::identifier) {
303 if (II == ObjcPropertyAttrs[objc_setter]) {
304 loc = ConsumeToken(); // consume method name
305 if (Tok.getKind() != tok::colon) {
306 Diag(loc, diag::err_expected_colon);
307 SkipUntil(tok::r_paren,true,true);
308 break;
309 }
310 }
311 }
312 else {
313 Diag(loc, diag::err_expected_ident);
314 SkipUntil(tok::r_paren,true,true);
315 break;
316 }
317 }
318 else {
319 Diag(loc, diag::err_objc_expected_equal);
320 SkipUntil(tok::r_paren,true,true);
321 break;
322 }
323 }
324 ConsumeToken(); // consume last attribute token
325 if (Tok.getKind() == tok::comma) {
326 loc = ConsumeToken();
327 continue;
328 }
329 if (Tok.getKind() == tok::r_paren)
330 break;
331 Diag(loc, diag::err_expected_rparen);
332 SkipUntil(tok::semi);
333 return;
334 }
335 if (Tok.getKind() == tok::r_paren)
336 ConsumeParen();
337 else {
338 Diag(loc, diag::err_objc_expected_property_attr);
339 SkipUntil(tok::r_paren); // recover from error inside attribute list
340 }
341}
342
343/// Main routine to parse property declaration.
344///
345/// @property property-attr-decl[opt] property-component-decl ';'
346///
347void Parser::ParseObjCPropertyDecl(DeclTy *interfaceDecl) {
348 assert(Tok.isObjCAtKeyword(tok::objc_property) &&
349 "ParseObjCPropertyDecl(): Expected @property");
350 ConsumeToken(); // the "property" identifier
351 // Parse property attribute list, if any.
352 if (Tok.getKind() == tok::l_paren) {
353 // property has attribute list.
354 ParseObjCPropertyAttribute(0/*FIXME*/);
355 }
356 // Parse declaration portion of @property.
357 llvm::SmallVector<DeclTy*, 32> PropertyDecls;
358 ParseStructDeclaration(interfaceDecl, PropertyDecls);
359 if (Tok.getKind() == tok::semi)
360 ConsumeToken();
361 else {
362 Diag(Tok, diag::err_expected_semi_decl_list);
363 SkipUntil(tok::r_brace, true, true);
364 }
Chris Lattner4b009652007-07-25 00:24:17 +0000365}
Steve Narofffb367882007-08-20 21:31:48 +0000366
Steve Naroff81f1bba2007-09-06 21:24:23 +0000367/// objc-method-proto:
Fariborz Jahanian027c23b2007-09-01 00:26:16 +0000368/// objc-instance-method objc-method-decl objc-method-attributes[opt]
Steve Naroff81f1bba2007-09-06 21:24:23 +0000369/// objc-class-method objc-method-decl objc-method-attributes[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000370///
371/// objc-instance-method: '-'
372/// objc-class-method: '+'
373///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000374/// objc-method-attributes: [OBJC2]
375/// __attribute__((deprecated))
376///
Fariborz Jahanian8b5ab6f2007-09-18 00:25:23 +0000377Parser::DeclTy *Parser::ParseObjCMethodPrototype(DeclTy *IDecl,
378 tok::ObjCKeywordKind MethodImplKind) {
Steve Naroff0bbffd82007-08-22 16:35:03 +0000379 assert((Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) &&
380 "expected +/-");
381
382 tok::TokenKind methodType = Tok.getKind();
383 SourceLocation methodLoc = ConsumeToken();
384
Fariborz Jahanian8b5ab6f2007-09-18 00:25:23 +0000385 DeclTy *MDecl = ParseObjCMethodDecl(methodType, methodLoc, MethodImplKind);
Steve Naroff81f1bba2007-09-06 21:24:23 +0000386 // Since this rule is used for both method declarations and definitions,
Steve Narofffaed3bf2007-09-10 20:51:04 +0000387 // the caller is (optionally) responsible for consuming the ';'.
Steve Naroff304ed392007-09-05 23:30:30 +0000388 return MDecl;
Steve Naroff0bbffd82007-08-22 16:35:03 +0000389}
390
391/// objc-selector:
392/// identifier
393/// one of
394/// enum struct union if else while do for switch case default
395/// break continue return goto asm sizeof typeof __alignof
396/// unsigned long const short volatile signed restrict _Complex
397/// in out inout bycopy byref oneway int char float double void _Bool
398///
399IdentifierInfo *Parser::ParseObjCSelector() {
400 tok::TokenKind tKind = Tok.getKind();
401 IdentifierInfo *II = 0;
Fariborz Jahanian171ceb52007-09-27 19:52:15 +0000402 switch (tKind) {
403 case tok::identifier:
404 case tok::kw_typeof:
405 case tok::kw___alignof:
406 case tok::kw_auto:
407 case tok::kw_break:
408 case tok::kw_case:
409 case tok::kw_char:
410 case tok::kw_const:
411 case tok::kw_continue:
412 case tok::kw_default:
413 case tok::kw_do:
414 case tok::kw_double:
415 case tok::kw_else:
416 case tok::kw_enum:
417 case tok::kw_extern:
418 case tok::kw_float:
419 case tok::kw_for:
420 case tok::kw_goto:
421 case tok::kw_if:
422 case tok::kw_inline:
423 case tok::kw_int:
424 case tok::kw_long:
425 case tok::kw_register:
426 case tok::kw_restrict:
427 case tok::kw_return:
428 case tok::kw_short:
429 case tok::kw_signed:
430 case tok::kw_sizeof:
431 case tok::kw_static:
432 case tok::kw_struct:
433 case tok::kw_switch:
434 case tok::kw_typedef:
435 case tok::kw_union:
436 case tok::kw_unsigned:
437 case tok::kw_void:
438 case tok::kw_volatile:
439 case tok::kw_while:
440 case tok::kw__Bool:
441 case tok::kw__Complex:
442 II = Tok.getIdentifierInfo();
443 ConsumeToken();
444 default:
445 break;
446 }
Steve Naroff0bbffd82007-08-22 16:35:03 +0000447
Steve Naroff0bbffd82007-08-22 16:35:03 +0000448 return II;
449}
450
Steve Naroffa8ee2262007-08-22 23:18:22 +0000451/// objc-type-qualifier: one of
452/// in out inout bycopy byref oneway
453///
Steve Naroffa8ee2262007-08-22 23:18:22 +0000454bool Parser::isObjCTypeQualifier() {
455 if (Tok.getKind() == tok::identifier) {
Chris Lattner32352462007-08-29 22:54:08 +0000456 const IdentifierInfo *II = Tok.getIdentifierInfo();
457 for (unsigned i = 0; i < objc_NumQuals; ++i)
458 if (II == ObjcTypeQuals[i]) return true;
Steve Naroffa8ee2262007-08-22 23:18:22 +0000459 }
460 return false;
461}
462
Fariborz Jahanian6668b8c2007-08-31 16:11:31 +0000463/// property-attrlist: one of
464/// readonly getter setter assign retain copy nonatomic
465///
466bool Parser::isObjCPropertyAttribute() {
467 if (Tok.getKind() == tok::identifier) {
468 const IdentifierInfo *II = Tok.getIdentifierInfo();
469 for (unsigned i = 0; i < objc_NumAttrs; ++i)
470 if (II == ObjcPropertyAttrs[i]) return true;
471 }
472 return false;
473}
474
Steve Naroff0bbffd82007-08-22 16:35:03 +0000475/// objc-type-name:
476/// '(' objc-type-qualifiers[opt] type-name ')'
477/// '(' objc-type-qualifiers[opt] ')'
478///
479/// objc-type-qualifiers:
480/// objc-type-qualifier
481/// objc-type-qualifiers objc-type-qualifier
482///
Steve Naroff304ed392007-09-05 23:30:30 +0000483Parser::TypeTy *Parser::ParseObjCTypeName() {
Steve Naroff0bbffd82007-08-22 16:35:03 +0000484 assert(Tok.getKind() == tok::l_paren && "expected (");
485
486 SourceLocation LParenLoc = ConsumeParen(), RParenLoc;
Chris Lattner265c8172007-09-27 15:15:46 +0000487 TypeTy *Ty = 0;
Steve Naroff0bbffd82007-08-22 16:35:03 +0000488
Steve Naroffa8ee2262007-08-22 23:18:22 +0000489 while (isObjCTypeQualifier())
490 ConsumeToken();
491
Steve Naroff0bbffd82007-08-22 16:35:03 +0000492 if (isTypeSpecifierQualifier()) {
Steve Naroff304ed392007-09-05 23:30:30 +0000493 Ty = ParseTypeName();
494 // FIXME: back when Sema support is in place...
495 // assert(Ty && "Parser::ParseObjCTypeName(): missing type");
Steve Naroff0bbffd82007-08-22 16:35:03 +0000496 }
497 if (Tok.getKind() != tok::r_paren) {
498 MatchRHSPunctuation(tok::r_paren, LParenLoc);
Steve Naroff304ed392007-09-05 23:30:30 +0000499 return 0; // FIXME: decide how we want to handle this error...
Steve Naroff0bbffd82007-08-22 16:35:03 +0000500 }
501 RParenLoc = ConsumeParen();
Steve Naroff304ed392007-09-05 23:30:30 +0000502 return Ty;
Steve Naroff0bbffd82007-08-22 16:35:03 +0000503}
504
Steve Naroff5b82d952007-09-28 23:39:26 +0000505unsigned Selector::getNumArgs() const {
506 unsigned IIF = getIdentifierInfoFlag();
507 if (IIF == ZeroArg)
508 return 0;
509 if (IIF == OneArg)
510 return 1;
511 // We point to a MultiKeywordSelector (pointer doesn't contain any flags).
512 MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
513 return SI->getNumArgs();
514}
515
516IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) {
517 IdentifierInfo *II = getAsIdentifierInfo();
518 if (II) {
519 assert(((argIndex == 0) || (argIndex == 1)) && "illegal keyword index");
520 return II;
521 }
522 // We point to a MultiKeywordSelector (pointer doesn't contain any flags).
523 MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
524 return SI->getIdentifierInfoForSlot(argIndex);
525}
526
527char *MultiKeywordSelector::getName(llvm::SmallVectorImpl<char> &methodName) {
528 methodName[0] = '\0';
529 keyword_iterator KeyIter = keyword_begin();
530 for (unsigned int i = 0; i < NumArgs; i++) {
531 if (KeyIter[i]) {
Steve Naroff96db8562007-10-02 02:01:22 +0000532 unsigned KeyLen = KeyIter[i]->getLength();
Steve Naroff5b82d952007-09-28 23:39:26 +0000533 methodName.append(KeyIter[i]->getName(), KeyIter[i]->getName()+KeyLen);
534 }
535 methodName.push_back(':');
536 }
537 methodName.push_back('\0');
538 return &methodName[0];
539}
540
541char *Selector::getName(llvm::SmallVectorImpl<char> &methodName) {
542 methodName[0] = '\0';
543 IdentifierInfo *II = getAsIdentifierInfo();
544 if (II) {
Steve Naroff96db8562007-10-02 02:01:22 +0000545 unsigned NameLen = II->getLength();
Steve Naroff5b82d952007-09-28 23:39:26 +0000546 methodName.append(II->getName(), II->getName()+NameLen);
547 if (getNumArgs() == 1)
548 methodName.push_back(':');
549 methodName.push_back('\0');
550 } else { // We have a multiple keyword selector (no embedded flags).
551 MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
552 SI->getName(methodName);
553 }
554 return &methodName[0];
555}
556
Steve Naroff6cb1d362007-09-28 22:22:11 +0000557Selector Parser::ObjcGetUnarySelector(IdentifierInfo *unarySel)
Steve Naroff4ed9d662007-09-27 14:38:14 +0000558{
Steve Naroff6cb1d362007-09-28 22:22:11 +0000559 return Selector(unarySel, 0);
Steve Naroff4ed9d662007-09-27 14:38:14 +0000560}
561
Steve Naroff6cb1d362007-09-28 22:22:11 +0000562Selector Parser::ObjcGetKeywordSelector(
563 llvm::SmallVectorImpl<IdentifierInfo *> &IIV)
564{
565 if (IIV.size() == 1)
566 return Selector(IIV[0], 1);
567
568 llvm::FoldingSet<MultiKeywordSelector> &SelTab = PP.getSelectorTable();
569
Steve Naroff4ed9d662007-09-27 14:38:14 +0000570 // Unique selector, to guarantee there is one per name.
571 llvm::FoldingSetNodeID ID;
Steve Naroff6cb1d362007-09-28 22:22:11 +0000572 MultiKeywordSelector::Profile(ID, &IIV[0], IIV.size());
Steve Naroff4ed9d662007-09-27 14:38:14 +0000573
574 void *InsertPos = 0;
Steve Naroff6cb1d362007-09-28 22:22:11 +0000575 if (MultiKeywordSelector *SI = SelTab.FindNodeOrInsertPos(ID, InsertPos)) {
576 return Selector(SI);
577 }
578 // MultiKeywordSelector objects are not allocated with new because they have a
Steve Naroff4ed9d662007-09-27 14:38:14 +0000579 // variable size array (for parameter types) at the end of them.
Steve Naroff6cb1d362007-09-28 22:22:11 +0000580 MultiKeywordSelector *SI =
581 (MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) +
582 IIV.size()*sizeof(IdentifierInfo *));
583 new (SI) MultiKeywordSelector(IIV.size(), &IIV[0]);
Steve Naroff4ed9d662007-09-27 14:38:14 +0000584 SelTab.InsertNode(SI, InsertPos);
Steve Naroff6cb1d362007-09-28 22:22:11 +0000585 return Selector(SI);
Steve Naroff4ed9d662007-09-27 14:38:14 +0000586}
587
Steve Naroff0bbffd82007-08-22 16:35:03 +0000588/// objc-method-decl:
589/// objc-selector
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000590/// objc-keyword-selector objc-parmlist[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000591/// objc-type-name objc-selector
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000592/// objc-type-name objc-keyword-selector objc-parmlist[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000593///
594/// objc-keyword-selector:
Steve Naroff72f17fb2007-08-22 22:17:26 +0000595/// objc-keyword-decl
Steve Naroff0bbffd82007-08-22 16:35:03 +0000596/// objc-keyword-selector objc-keyword-decl
597///
598/// objc-keyword-decl:
Steve Naroff72f17fb2007-08-22 22:17:26 +0000599/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
600/// objc-selector ':' objc-keyword-attributes[opt] identifier
601/// ':' objc-type-name objc-keyword-attributes[opt] identifier
602/// ':' objc-keyword-attributes[opt] identifier
Steve Naroff0bbffd82007-08-22 16:35:03 +0000603///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000604/// objc-parmlist:
605/// objc-parms objc-ellipsis[opt]
Steve Naroff0bbffd82007-08-22 16:35:03 +0000606///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000607/// objc-parms:
608/// objc-parms , parameter-declaration
Steve Naroff0bbffd82007-08-22 16:35:03 +0000609///
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000610/// objc-ellipsis:
Steve Naroff0bbffd82007-08-22 16:35:03 +0000611/// , ...
612///
Steve Naroff72f17fb2007-08-22 22:17:26 +0000613/// objc-keyword-attributes: [OBJC2]
614/// __attribute__((unused))
615///
Steve Naroff4ed9d662007-09-27 14:38:14 +0000616Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType,
617 SourceLocation mLoc,
618 tok::ObjCKeywordKind MethodImplKind)
619{
Steve Naroff304ed392007-09-05 23:30:30 +0000620 TypeTy *ReturnType = 0;
Fariborz Jahanian3dc7cbc2007-09-10 20:33:04 +0000621 AttributeList *methodAttrs = 0;
Steve Naroff304ed392007-09-05 23:30:30 +0000622
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000623 // Parse the return type.
Steve Naroff0bbffd82007-08-22 16:35:03 +0000624 if (Tok.getKind() == tok::l_paren)
Steve Naroff304ed392007-09-05 23:30:30 +0000625 ReturnType = ParseObjCTypeName();
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000626 IdentifierInfo *selIdent = ParseObjCSelector();
Steve Naroff304ed392007-09-05 23:30:30 +0000627
Steve Naroff4ed9d662007-09-27 14:38:14 +0000628 llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
629 llvm::SmallVector<Action::TypeTy *, 12> KeyTypes;
630 llvm::SmallVector<IdentifierInfo *, 12> ArgNames;
631
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000632 if (Tok.getKind() == tok::colon) {
Steve Naroff4ed9d662007-09-27 14:38:14 +0000633 Action::TypeTy *TypeInfo;
Steve Naroff304ed392007-09-05 23:30:30 +0000634
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000635 while (1) {
Steve Naroff4ed9d662007-09-27 14:38:14 +0000636 KeyIdents.push_back(selIdent);
Steve Naroff304ed392007-09-05 23:30:30 +0000637
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000638 // Each iteration parses a single keyword argument.
639 if (Tok.getKind() != tok::colon) {
640 Diag(Tok, diag::err_expected_colon);
641 break;
642 }
Steve Naroff4ed9d662007-09-27 14:38:14 +0000643 ConsumeToken(); // Eat the ':'.
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000644 if (Tok.getKind() == tok::l_paren) // Parse the argument type.
Steve Naroff4ed9d662007-09-27 14:38:14 +0000645 TypeInfo = ParseObjCTypeName();
646 else
647 TypeInfo = 0;
648 KeyTypes.push_back(TypeInfo);
649
Steve Naroff72f17fb2007-08-22 22:17:26 +0000650 // If attributes exist before the argument name, parse them.
Steve Naroffa7f62782007-08-23 19:56:30 +0000651 if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
Steve Naroff4ed9d662007-09-27 14:38:14 +0000652 ParseAttributes(); // FIXME: pass attributes through.
Steve Naroff72f17fb2007-08-22 22:17:26 +0000653
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000654 if (Tok.getKind() != tok::identifier) {
655 Diag(Tok, diag::err_expected_ident); // missing argument name.
656 break;
657 }
Steve Naroff4ed9d662007-09-27 14:38:14 +0000658 ArgNames.push_back(Tok.getIdentifierInfo());
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000659 ConsumeToken(); // Eat the identifier.
Steve Naroff304ed392007-09-05 23:30:30 +0000660
Steve Naroff253118b2007-09-17 20:25:27 +0000661 // Check for another keyword selector.
Steve Naroff304ed392007-09-05 23:30:30 +0000662 selIdent = ParseObjCSelector();
663 if (!selIdent && Tok.getKind() != tok::colon)
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000664 break;
665 // We have a selector or a colon, continue parsing.
666 }
667 // Parse the (optional) parameter list.
668 while (Tok.getKind() == tok::comma) {
669 ConsumeToken();
670 if (Tok.getKind() == tok::ellipsis) {
671 ConsumeToken();
672 break;
673 }
Fariborz Jahanian1e534dc2007-09-05 19:52:07 +0000674 // Parse the c-style argument declaration-specifier.
675 DeclSpec DS;
676 ParseDeclarationSpecifiers(DS);
677 // Parse the declarator.
678 Declarator ParmDecl(DS, Declarator::PrototypeContext);
679 ParseDeclarator(ParmDecl);
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000680 }
Steve Naroff304ed392007-09-05 23:30:30 +0000681 // FIXME: Add support for optional parmameter list...
Fariborz Jahanian3dc7cbc2007-09-10 20:33:04 +0000682 // If attributes exist after the method, parse them.
683 if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
684 methodAttrs = ParseAttributes();
Steve Naroff4ed9d662007-09-27 14:38:14 +0000685
Steve Naroff6cb1d362007-09-28 22:22:11 +0000686 Selector Sel = ObjcGetKeywordSelector(KeyIdents);
Steve Naroffb4dfe362007-10-02 22:39:18 +0000687 return Actions.ActOnMethodDeclaration(mLoc, mType, ReturnType, Sel,
688 &KeyTypes[0], &ArgNames[0],
689 methodAttrs, MethodImplKind);
Steve Naroff09a0c4c2007-08-22 18:35:33 +0000690 } else if (!selIdent) {
691 Diag(Tok, diag::err_expected_ident); // missing selector name.
692 }
Fariborz Jahanian3dc7cbc2007-09-10 20:33:04 +0000693 // If attributes exist after the method, parse them.
694 if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
695 methodAttrs = ParseAttributes();
696
Steve Naroff6cb1d362007-09-28 22:22:11 +0000697 Selector Sel = ObjcGetUnarySelector(selIdent);
Steve Naroffb4dfe362007-10-02 22:39:18 +0000698 return Actions.ActOnMethodDeclaration(mLoc, mType, ReturnType, Sel,
699 0, 0, methodAttrs, MethodImplKind);
Steve Naroff0bbffd82007-08-22 16:35:03 +0000700}
701
Steve Narofffb367882007-08-20 21:31:48 +0000702/// objc-protocol-refs:
703/// '<' identifier-list '>'
704///
Steve Naroff304ed392007-09-05 23:30:30 +0000705bool Parser::ParseObjCProtocolReferences(
706 llvm::SmallVectorImpl<IdentifierInfo*> &ProtocolRefs) {
Steve Narofffb367882007-08-20 21:31:48 +0000707 assert(Tok.getKind() == tok::less && "expected <");
708
709 ConsumeToken(); // the "<"
Steve Narofffb367882007-08-20 21:31:48 +0000710
711 while (1) {
712 if (Tok.getKind() != tok::identifier) {
713 Diag(Tok, diag::err_expected_ident);
714 SkipUntil(tok::greater);
715 return true;
716 }
717 ProtocolRefs.push_back(Tok.getIdentifierInfo());
718 ConsumeToken();
719
720 if (Tok.getKind() != tok::comma)
721 break;
722 ConsumeToken();
723 }
724 // Consume the '>'.
725 return ExpectAndConsume(tok::greater, diag::err_expected_greater);
726}
727
728/// objc-class-instance-variables:
729/// '{' objc-instance-variable-decl-list[opt] '}'
730///
731/// objc-instance-variable-decl-list:
732/// objc-visibility-spec
733/// objc-instance-variable-decl ';'
734/// ';'
735/// objc-instance-variable-decl-list objc-visibility-spec
736/// objc-instance-variable-decl-list objc-instance-variable-decl ';'
737/// objc-instance-variable-decl-list ';'
738///
739/// objc-visibility-spec:
740/// @private
741/// @protected
742/// @public
Steve Naroffc4474992007-08-21 21:17:12 +0000743/// @package [OBJC2]
Steve Narofffb367882007-08-20 21:31:48 +0000744///
745/// objc-instance-variable-decl:
746/// struct-declaration
747///
Steve Naroff81f1bba2007-09-06 21:24:23 +0000748void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl) {
Steve Naroffc4474992007-08-21 21:17:12 +0000749 assert(Tok.getKind() == tok::l_brace && "expected {");
Steve Naroff81f1bba2007-09-06 21:24:23 +0000750 llvm::SmallVector<DeclTy*, 16> IvarDecls;
Fariborz Jahanian3957dae2007-09-13 20:56:13 +0000751 llvm::SmallVector<DeclTy*, 32> AllIvarDecls;
752 llvm::SmallVector<tok::ObjCKeywordKind, 32> AllVisibilities;
Steve Naroffc4474992007-08-21 21:17:12 +0000753
754 SourceLocation LBraceLoc = ConsumeBrace(); // the "{"
Steve Naroffc4474992007-08-21 21:17:12 +0000755
Fariborz Jahanian3957dae2007-09-13 20:56:13 +0000756 tok::ObjCKeywordKind visibility = tok::objc_private;
Steve Naroffc4474992007-08-21 21:17:12 +0000757 // While we still have something to read, read the instance variables.
758 while (Tok.getKind() != tok::r_brace &&
759 Tok.getKind() != tok::eof) {
760 // Each iteration of this loop reads one objc-instance-variable-decl.
761
762 // Check for extraneous top-level semicolon.
763 if (Tok.getKind() == tok::semi) {
764 Diag(Tok, diag::ext_extra_struct_semi);
765 ConsumeToken();
766 continue;
767 }
768 // Set the default visibility to private.
Steve Naroffc4474992007-08-21 21:17:12 +0000769 if (Tok.getKind() == tok::at) { // parse objc-visibility-spec
770 ConsumeToken(); // eat the @ sign
Steve Naroff87c329f2007-08-23 18:16:40 +0000771 switch (Tok.getObjCKeywordID()) {
Steve Naroffc4474992007-08-21 21:17:12 +0000772 case tok::objc_private:
773 case tok::objc_public:
774 case tok::objc_protected:
775 case tok::objc_package:
Steve Naroff87c329f2007-08-23 18:16:40 +0000776 visibility = Tok.getObjCKeywordID();
Steve Naroffc4474992007-08-21 21:17:12 +0000777 ConsumeToken();
778 continue;
779 default:
780 Diag(Tok, diag::err_objc_illegal_visibility_spec);
781 ConsumeToken();
782 continue;
783 }
784 }
785 ParseStructDeclaration(interfaceDecl, IvarDecls);
Fariborz Jahanian3957dae2007-09-13 20:56:13 +0000786 for (unsigned i = 0; i < IvarDecls.size(); i++) {
787 AllIvarDecls.push_back(IvarDecls[i]);
788 AllVisibilities.push_back(visibility);
789 }
Steve Naroff81f1bba2007-09-06 21:24:23 +0000790 IvarDecls.clear();
791
Steve Naroffc4474992007-08-21 21:17:12 +0000792 if (Tok.getKind() == tok::semi) {
793 ConsumeToken();
794 } else if (Tok.getKind() == tok::r_brace) {
795 Diag(Tok.getLocation(), diag::ext_expected_semi_decl_list);
796 break;
797 } else {
798 Diag(Tok, diag::err_expected_semi_decl_list);
799 // Skip to end of block or statement
800 SkipUntil(tok::r_brace, true, true);
801 }
802 }
Fariborz Jahanian3957dae2007-09-13 20:56:13 +0000803 if (AllIvarDecls.size()) { // Check for {} - no ivars in braces
Fariborz Jahanian0c5affb2007-09-29 00:54:24 +0000804 Actions.ActOnFields(CurScope, LBraceLoc, interfaceDecl,
Steve Naroff0acc9c92007-09-15 18:49:24 +0000805 &AllIvarDecls[0], AllIvarDecls.size(),
806 &AllVisibilities[0]);
Fariborz Jahanian3957dae2007-09-13 20:56:13 +0000807 }
Steve Naroffc4474992007-08-21 21:17:12 +0000808 MatchRHSPunctuation(tok::r_brace, LBraceLoc);
809 return;
Chris Lattner4b009652007-07-25 00:24:17 +0000810}
Steve Narofffb367882007-08-20 21:31:48 +0000811
812/// objc-protocol-declaration:
813/// objc-protocol-definition
814/// objc-protocol-forward-reference
815///
816/// objc-protocol-definition:
817/// @protocol identifier
818/// objc-protocol-refs[opt]
Steve Naroff81f1bba2007-09-06 21:24:23 +0000819/// objc-interface-decl-list
Steve Narofffb367882007-08-20 21:31:48 +0000820/// @end
821///
822/// objc-protocol-forward-reference:
823/// @protocol identifier-list ';'
824///
825/// "@protocol identifier ;" should be resolved as "@protocol
Steve Naroff81f1bba2007-09-06 21:24:23 +0000826/// identifier-list ;": objc-interface-decl-list may not start with a
Steve Narofffb367882007-08-20 21:31:48 +0000827/// semicolon in the first alternative if objc-protocol-refs are omitted.
828
Steve Naroff72f17fb2007-08-22 22:17:26 +0000829Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) {
Steve Naroff87c329f2007-08-23 18:16:40 +0000830 assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
Steve Naroff72f17fb2007-08-22 22:17:26 +0000831 "ParseObjCAtProtocolDeclaration(): Expected @protocol");
832 ConsumeToken(); // the "protocol" identifier
833
834 if (Tok.getKind() != tok::identifier) {
835 Diag(Tok, diag::err_expected_ident); // missing protocol name.
836 return 0;
837 }
838 // Save the protocol name, then consume it.
839 IdentifierInfo *protocolName = Tok.getIdentifierInfo();
840 SourceLocation nameLoc = ConsumeToken();
841
Fariborz Jahanianc716c942007-09-21 15:40:54 +0000842 llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
843 if (Tok.getKind() == tok::semi) { // forward declaration of one protocol.
Steve Naroff72f17fb2007-08-22 22:17:26 +0000844 ConsumeToken();
Fariborz Jahanianc716c942007-09-21 15:40:54 +0000845 ProtocolRefs.push_back(protocolName);
Steve Naroff72f17fb2007-08-22 22:17:26 +0000846 }
847 if (Tok.getKind() == tok::comma) { // list of forward declarations.
848 // Parse the list of forward declarations.
Steve Naroff72f17fb2007-08-22 22:17:26 +0000849 ProtocolRefs.push_back(protocolName);
850
851 while (1) {
852 ConsumeToken(); // the ','
853 if (Tok.getKind() != tok::identifier) {
854 Diag(Tok, diag::err_expected_ident);
855 SkipUntil(tok::semi);
856 return 0;
857 }
858 ProtocolRefs.push_back(Tok.getIdentifierInfo());
859 ConsumeToken(); // the identifier
860
861 if (Tok.getKind() != tok::comma)
862 break;
863 }
864 // Consume the ';'.
865 if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
866 return 0;
Steve Naroff72f17fb2007-08-22 22:17:26 +0000867 }
Fariborz Jahanianc716c942007-09-21 15:40:54 +0000868 if (ProtocolRefs.size() > 0)
Steve Naroffb4dfe362007-10-02 22:39:18 +0000869 return Actions.ActOnForwardProtocolDeclaration(CurScope, AtLoc,
870 &ProtocolRefs[0],
871 ProtocolRefs.size());
Steve Naroff72f17fb2007-08-22 22:17:26 +0000872 // Last, and definitely not least, parse a protocol declaration.
873 if (Tok.getKind() == tok::less) {
Steve Naroff304ed392007-09-05 23:30:30 +0000874 if (ParseObjCProtocolReferences(ProtocolRefs))
Steve Naroff72f17fb2007-08-22 22:17:26 +0000875 return 0;
876 }
Fariborz Jahanian63ca8ae2007-09-17 21:07:36 +0000877
Fariborz Jahanianc091b5d2007-09-25 18:38:09 +0000878 DeclTy *ProtoType = Actions.ObjcStartProtoInterface(CurScope, AtLoc,
Fariborz Jahanian63ca8ae2007-09-17 21:07:36 +0000879 protocolName, nameLoc,
880 &ProtocolRefs[0],
881 ProtocolRefs.size());
882 ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol);
Steve Naroff72f17fb2007-08-22 22:17:26 +0000883
884 // The @ sign was already consumed by ParseObjCInterfaceDeclList().
Steve Naroff87c329f2007-08-23 18:16:40 +0000885 if (Tok.isObjCAtKeyword(tok::objc_end)) {
Steve Naroff72f17fb2007-08-22 22:17:26 +0000886 ConsumeToken(); // the "end" identifier
887 return 0;
888 }
889 Diag(Tok, diag::err_objc_missing_end);
Steve Narofffb367882007-08-20 21:31:48 +0000890 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +0000891}
Steve Narofffb367882007-08-20 21:31:48 +0000892
893/// objc-implementation:
894/// objc-class-implementation-prologue
895/// objc-category-implementation-prologue
896///
897/// objc-class-implementation-prologue:
898/// @implementation identifier objc-superclass[opt]
899/// objc-class-instance-variables[opt]
900///
901/// objc-category-implementation-prologue:
902/// @implementation identifier ( identifier )
903
Fariborz Jahanian027c23b2007-09-01 00:26:16 +0000904Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration(
905 SourceLocation atLoc) {
906 assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
907 "ParseObjCAtImplementationDeclaration(): Expected @implementation");
908 ConsumeToken(); // the "implementation" identifier
909
910 if (Tok.getKind() != tok::identifier) {
911 Diag(Tok, diag::err_expected_ident); // missing class or category name.
912 return 0;
913 }
914 // We have a class or category name - consume it.
Fariborz Jahanianc091b5d2007-09-25 18:38:09 +0000915 IdentifierInfo *nameId = Tok.getIdentifierInfo();
Fariborz Jahanian027c23b2007-09-01 00:26:16 +0000916 SourceLocation nameLoc = ConsumeToken(); // consume class or category name
917
918 if (Tok.getKind() == tok::l_paren) {
919 // we have a category implementation.
920 SourceLocation lparenLoc = ConsumeParen();
921 SourceLocation categoryLoc, rparenLoc;
922 IdentifierInfo *categoryId = 0;
923
924 if (Tok.getKind() == tok::identifier) {
925 categoryId = Tok.getIdentifierInfo();
926 categoryLoc = ConsumeToken();
927 } else {
928 Diag(Tok, diag::err_expected_ident); // missing category name.
929 return 0;
930 }
931 if (Tok.getKind() != tok::r_paren) {
932 Diag(Tok, diag::err_expected_rparen);
933 SkipUntil(tok::r_paren, false); // don't stop at ';'
934 return 0;
935 }
936 rparenLoc = ConsumeParen();
Fariborz Jahaniana91aa322007-10-02 16:38:50 +0000937 DeclTy *ImplCatType = Actions.ObjcStartCategoryImplementation(CurScope,
938 atLoc, nameId, nameLoc, categoryId,
939 categoryLoc);
940 return ImplCatType;
Fariborz Jahanian027c23b2007-09-01 00:26:16 +0000941 }
942 // We have a class implementation
Fariborz Jahanianc091b5d2007-09-25 18:38:09 +0000943 SourceLocation superClassLoc;
944 IdentifierInfo *superClassId = 0;
Fariborz Jahanian027c23b2007-09-01 00:26:16 +0000945 if (Tok.getKind() == tok::colon) {
946 // We have a super class
947 ConsumeToken();
948 if (Tok.getKind() != tok::identifier) {
949 Diag(Tok, diag::err_expected_ident); // missing super class name.
950 return 0;
951 }
Fariborz Jahanianc091b5d2007-09-25 18:38:09 +0000952 superClassId = Tok.getIdentifierInfo();
953 superClassLoc = ConsumeToken(); // Consume super class name
Fariborz Jahanian027c23b2007-09-01 00:26:16 +0000954 }
Fariborz Jahanianc091b5d2007-09-25 18:38:09 +0000955 DeclTy *ImplClsType = Actions.ObjcStartClassImplementation(CurScope,
956 atLoc,
957 nameId, nameLoc,
958 superClassId, superClassLoc);
959
Fariborz Jahanian027c23b2007-09-01 00:26:16 +0000960 if (Tok.getKind() == tok::l_brace)
Fariborz Jahanianc091b5d2007-09-25 18:38:09 +0000961 ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/); // we have ivars
Fariborz Jahanian027c23b2007-09-01 00:26:16 +0000962
Fariborz Jahanian1e4e82f2007-09-27 18:57:03 +0000963 return ImplClsType;
Chris Lattner4b009652007-07-25 00:24:17 +0000964}
Fariborz Jahanian027c23b2007-09-01 00:26:16 +0000965Parser::DeclTy *Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) {
966 assert(Tok.isObjCAtKeyword(tok::objc_end) &&
967 "ParseObjCAtEndDeclaration(): Expected @end");
968 ConsumeToken(); // the "end" identifier
Fariborz Jahanian1e4e82f2007-09-27 18:57:03 +0000969 if (ObjcImpDecl) {
970 // Checking is not necessary except that a parse error might have caused
971 // @implementation not to have been parsed to completion and ObjcImpDecl
972 // could be 0.
973 /// Insert collected methods declarations into the @interface object.
Fariborz Jahanian0c5affb2007-09-29 00:54:24 +0000974 Actions.ObjcAddMethodsToClass(CurScope, ObjcImpDecl,
Fariborz Jahanian1e4e82f2007-09-27 18:57:03 +0000975 &AllImplMethods[0],AllImplMethods.size());
976 ObjcImpDecl = 0;
977 AllImplMethods.clear();
978 }
Fariborz Jahanian027c23b2007-09-01 00:26:16 +0000979
Steve Narofffb367882007-08-20 21:31:48 +0000980 return 0;
981}
Fariborz Jahanianb62aff32007-09-04 19:26:51 +0000982
983/// compatibility-alias-decl:
984/// @compatibility_alias alias-name class-name ';'
985///
986Parser::DeclTy *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
987 assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
988 "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
989 ConsumeToken(); // consume compatibility_alias
990 if (Tok.getKind() != tok::identifier) {
991 Diag(Tok, diag::err_expected_ident);
992 return 0;
993 }
994 ConsumeToken(); // consume alias-name
995 if (Tok.getKind() != tok::identifier) {
996 Diag(Tok, diag::err_expected_ident);
997 return 0;
998 }
999 ConsumeToken(); // consume class-name;
1000 if (Tok.getKind() != tok::semi)
Fariborz Jahanian6c30fa62007-09-04 21:42:12 +00001001 Diag(Tok, diag::err_expected_semi_after, "@compatibility_alias");
Steve Narofffb367882007-08-20 21:31:48 +00001002 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +00001003}
1004
Fariborz Jahanian027c23b2007-09-01 00:26:16 +00001005/// property-synthesis:
1006/// @synthesize property-ivar-list ';'
1007///
1008/// property-ivar-list:
1009/// property-ivar
1010/// property-ivar-list ',' property-ivar
1011///
1012/// property-ivar:
1013/// identifier
1014/// identifier '=' identifier
1015///
1016Parser::DeclTy *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
1017 assert(Tok.isObjCAtKeyword(tok::objc_synthesize) &&
1018 "ParseObjCPropertyDynamic(): Expected '@synthesize'");
1019 SourceLocation loc = ConsumeToken(); // consume dynamic
1020 if (Tok.getKind() != tok::identifier) {
1021 Diag(Tok, diag::err_expected_ident);
1022 return 0;
1023 }
1024 while (Tok.getKind() == tok::identifier) {
1025 ConsumeToken(); // consume property name
1026 if (Tok.getKind() == tok::equal) {
1027 // property '=' ivar-name
1028 ConsumeToken(); // consume '='
1029 if (Tok.getKind() != tok::identifier) {
1030 Diag(Tok, diag::err_expected_ident);
1031 break;
1032 }
1033 ConsumeToken(); // consume ivar-name
1034 }
1035 if (Tok.getKind() != tok::comma)
1036 break;
1037 ConsumeToken(); // consume ','
1038 }
1039 if (Tok.getKind() != tok::semi)
1040 Diag(Tok, diag::err_expected_semi_after, "@synthesize");
1041 return 0;
Chris Lattner4b009652007-07-25 00:24:17 +00001042}
1043
Fariborz Jahanian027c23b2007-09-01 00:26:16 +00001044/// property-dynamic:
1045/// @dynamic property-list
1046///
1047/// property-list:
1048/// identifier
1049/// property-list ',' identifier
1050///
1051Parser::DeclTy *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
1052 assert(Tok.isObjCAtKeyword(tok::objc_dynamic) &&
1053 "ParseObjCPropertyDynamic(): Expected '@dynamic'");
1054 SourceLocation loc = ConsumeToken(); // consume dynamic
1055 if (Tok.getKind() != tok::identifier) {
1056 Diag(Tok, diag::err_expected_ident);
1057 return 0;
1058 }
1059 while (Tok.getKind() == tok::identifier) {
1060 ConsumeToken(); // consume property name
1061 if (Tok.getKind() != tok::comma)
1062 break;
1063 ConsumeToken(); // consume ','
1064 }
1065 if (Tok.getKind() != tok::semi)
1066 Diag(Tok, diag::err_expected_semi_after, "@dynamic");
1067 return 0;
1068}
Fariborz Jahanian64b864e2007-09-19 19:14:32 +00001069
1070/// objc-throw-statement:
1071/// throw expression[opt];
1072///
1073Parser::DeclTy *Parser::ParseObjCThrowStmt(SourceLocation &atLoc) {
1074 ConsumeToken(); // consume throw
1075 if (Tok.getKind() != tok::semi) {
1076 ExprResult Res = ParseAssignmentExpression();
1077 if (Res.isInvalid) {
1078 SkipUntil(tok::semi);
1079 return 0;
1080 }
1081 }
1082 return 0;
1083}
1084
1085/// objc-try-catch-statement:
1086/// @try compound-statement objc-catch-list[opt]
1087/// @try compound-statement objc-catch-list[opt] @finally compound-statement
1088///
1089/// objc-catch-list:
1090/// @catch ( parameter-declaration ) compound-statement
1091/// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement
1092/// catch-parameter-declaration:
1093/// parameter-declaration
1094/// '...' [OBJC2]
1095///
1096Parser::DeclTy *Parser::ParseObjCTryStmt(SourceLocation &atLoc) {
1097 bool catch_or_finally_seen = false;
1098 ConsumeToken(); // consume try
1099 if (Tok.getKind() != tok::l_brace) {
1100 Diag (Tok, diag::err_expected_lbrace);
1101 return 0;
1102 }
1103 StmtResult TryBody = ParseCompoundStatementBody();
1104 while (Tok.getKind() == tok::at) {
1105 ConsumeToken();
1106 if (Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_catch) {
1107 SourceLocation catchLoc = ConsumeToken(); // consume catch
1108 if (Tok.getKind() == tok::l_paren) {
1109 ConsumeParen();
1110 if (Tok.getKind() != tok::ellipsis) {
1111 DeclSpec DS;
1112 ParseDeclarationSpecifiers(DS);
1113 // Parse the parameter-declaration.
1114 // FIXME: BlockContext may not be the right context!
1115 Declarator ParmDecl(DS, Declarator::BlockContext);
1116 ParseDeclarator(ParmDecl);
1117 }
1118 else
1119 ConsumeToken(); // consume '...'
1120 ConsumeParen();
1121 StmtResult CatchMody = ParseCompoundStatementBody();
1122 }
1123 else {
1124 Diag(catchLoc, diag::err_expected_lparen_after, "@catch clause");
1125 return 0;
1126 }
1127 catch_or_finally_seen = true;
1128 }
1129 else if (Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_finally) {
1130 ConsumeToken(); // consume finally
1131 StmtResult FinallyBody = ParseCompoundStatementBody();
1132 catch_or_finally_seen = true;
1133 break;
1134 }
1135 }
1136 if (!catch_or_finally_seen)
1137 Diag(atLoc, diag::err_missing_catch_finally);
1138 return 0;
1139}
Fariborz Jahanian027c23b2007-09-01 00:26:16 +00001140
Steve Naroff81f1bba2007-09-06 21:24:23 +00001141/// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
Fariborz Jahanian027c23b2007-09-01 00:26:16 +00001142///
1143void Parser::ParseObjCInstanceMethodDefinition() {
1144 assert(Tok.getKind() == tok::minus &&
1145 "ParseObjCInstanceMethodDefinition(): Expected '-'");
Fariborz Jahanian63ca8ae2007-09-17 21:07:36 +00001146 // FIXME: @optional/@protocol??
Fariborz Jahanian1e4e82f2007-09-27 18:57:03 +00001147 AllImplMethods.push_back(ParseObjCMethodPrototype(ObjcImpDecl));
Fariborz Jahanian027c23b2007-09-01 00:26:16 +00001148 // parse optional ';'
1149 if (Tok.getKind() == tok::semi)
1150 ConsumeToken();
1151
1152 if (Tok.getKind() != tok::l_brace) {
1153 Diag (Tok, diag::err_expected_lbrace);
1154 return;
1155 }
1156
1157 StmtResult FnBody = ParseCompoundStatementBody();
1158}
1159
Steve Naroff81f1bba2007-09-06 21:24:23 +00001160/// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
Fariborz Jahanian027c23b2007-09-01 00:26:16 +00001161///
Steve Naroff72f17fb2007-08-22 22:17:26 +00001162void Parser::ParseObjCClassMethodDefinition() {
Fariborz Jahanian027c23b2007-09-01 00:26:16 +00001163 assert(Tok.getKind() == tok::plus &&
1164 "ParseObjCClassMethodDefinition(): Expected '+'");
Fariborz Jahanian63ca8ae2007-09-17 21:07:36 +00001165 // FIXME: @optional/@protocol??
Fariborz Jahanian1e4e82f2007-09-27 18:57:03 +00001166 AllImplMethods.push_back(ParseObjCMethodPrototype(ObjcImpDecl));
Fariborz Jahanian027c23b2007-09-01 00:26:16 +00001167 // parse optional ';'
1168 if (Tok.getKind() == tok::semi)
1169 ConsumeToken();
1170 if (Tok.getKind() != tok::l_brace) {
1171 Diag (Tok, diag::err_expected_lbrace);
1172 return;
1173 }
1174
1175 StmtResult FnBody = ParseCompoundStatementBody();
Chris Lattner4b009652007-07-25 00:24:17 +00001176}
Anders Carlssona66cad42007-08-21 17:43:55 +00001177
Fariborz Jahanian64b864e2007-09-19 19:14:32 +00001178Parser::ExprResult Parser::ParseObjCExpression(SourceLocation &AtLoc) {
Anders Carlssona66cad42007-08-21 17:43:55 +00001179
1180 switch (Tok.getKind()) {
1181 case tok::string_literal: // primary-expression: string-literal
1182 case tok::wide_string_literal:
1183 return ParseObjCStringLiteral();
Anders Carlsson2996b4e2007-08-23 15:25:28 +00001184 default:
1185 break;
1186 }
1187
1188 switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
Anders Carlsson8be1d402007-08-22 15:14:15 +00001189 case tok::objc_encode:
1190 return ParseObjCEncodeExpression();
Anders Carlsson2996b4e2007-08-23 15:25:28 +00001191 case tok::objc_protocol:
1192 return ParseObjCProtocolExpression();
Anders Carlssona66cad42007-08-21 17:43:55 +00001193 default:
1194 Diag(AtLoc, diag::err_unexpected_at);
1195 SkipUntil(tok::semi);
1196 break;
1197 }
1198
1199 return 0;
1200}
1201
Fariborz Jahanian1e534dc2007-09-05 19:52:07 +00001202/// objc-message-expr:
1203/// '[' objc-receiver objc-message-args ']'
1204///
1205/// objc-receiver:
1206/// expression
1207/// class-name
1208/// type-name
1209///
1210/// objc-message-args:
1211/// objc-selector
1212/// objc-keywordarg-list
1213///
1214/// objc-keywordarg-list:
1215/// objc-keywordarg
1216/// objc-keywordarg-list objc-keywordarg
1217///
1218/// objc-keywordarg:
1219/// selector-name[opt] ':' objc-keywordexpr
1220///
1221/// objc-keywordexpr:
1222/// nonempty-expr-list
1223///
1224/// nonempty-expr-list:
1225/// assignment-expression
1226/// nonempty-expr-list , assignment-expression
1227///
1228Parser::ExprResult Parser::ParseObjCMessageExpression() {
Fariborz Jahaniand4462f92007-09-05 23:08:20 +00001229 assert(Tok.getKind() == tok::l_square && "'[' expected");
Steve Naroffc39ca262007-09-18 23:55:05 +00001230 SourceLocation LBracloc = ConsumeBracket(); // consume '['
Steve Naroff253118b2007-09-17 20:25:27 +00001231 IdentifierInfo *ReceiverName = 0;
1232 ExprTy *ReceiverExpr = 0;
Fariborz Jahaniand4462f92007-09-05 23:08:20 +00001233 // Parse receiver
Steve Narofff0c31dd2007-09-16 16:16:00 +00001234 if (Tok.getKind() == tok::identifier &&
Steve Naroff253118b2007-09-17 20:25:27 +00001235 Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) {
1236 ReceiverName = Tok.getIdentifierInfo();
Steve Narofff0c31dd2007-09-16 16:16:00 +00001237 ConsumeToken();
Steve Naroff253118b2007-09-17 20:25:27 +00001238 } else {
1239 ExprResult Res = ParseAssignmentExpression();
1240 if (Res.isInvalid) {
1241 SkipUntil(tok::identifier);
1242 return Res;
1243 }
1244 ReceiverExpr = Res.Val;
1245 }
Fariborz Jahaniand4462f92007-09-05 23:08:20 +00001246 // Parse objc-selector
1247 IdentifierInfo *selIdent = ParseObjCSelector();
Steve Naroff4ed9d662007-09-27 14:38:14 +00001248
1249 llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
1250 llvm::SmallVector<Action::ExprTy *, 12> KeyExprs;
1251
Fariborz Jahaniand4462f92007-09-05 23:08:20 +00001252 if (Tok.getKind() == tok::colon) {
1253 while (1) {
1254 // Each iteration parses a single keyword argument.
Steve Naroff4ed9d662007-09-27 14:38:14 +00001255 KeyIdents.push_back(selIdent);
Steve Naroff253118b2007-09-17 20:25:27 +00001256
Fariborz Jahaniand4462f92007-09-05 23:08:20 +00001257 if (Tok.getKind() != tok::colon) {
1258 Diag(Tok, diag::err_expected_colon);
1259 SkipUntil(tok::semi);
Steve Naroff253118b2007-09-17 20:25:27 +00001260 return true;
Fariborz Jahaniand4462f92007-09-05 23:08:20 +00001261 }
Steve Naroff4ed9d662007-09-27 14:38:14 +00001262 ConsumeToken(); // Eat the ':'.
Fariborz Jahaniand4462f92007-09-05 23:08:20 +00001263 /// Parse the expression after ':'
Steve Naroff253118b2007-09-17 20:25:27 +00001264 ExprResult Res = ParseAssignmentExpression();
1265 if (Res.isInvalid) {
1266 SkipUntil(tok::identifier);
1267 return Res;
1268 }
1269 // We have a valid expression.
Steve Naroff4ed9d662007-09-27 14:38:14 +00001270 KeyExprs.push_back(Res.Val);
Steve Naroff253118b2007-09-17 20:25:27 +00001271
1272 // Check for another keyword selector.
1273 selIdent = ParseObjCSelector();
1274 if (!selIdent && Tok.getKind() != tok::colon)
Fariborz Jahaniand4462f92007-09-05 23:08:20 +00001275 break;
1276 // We have a selector or a colon, continue parsing.
1277 }
1278 // Parse the, optional, argument list, comma separated.
1279 while (Tok.getKind() == tok::comma) {
1280 ConsumeToken();
1281 /// Parse the expression after ','
1282 ParseAssignmentExpression();
1283 }
1284 } else if (!selIdent) {
1285 Diag(Tok, diag::err_expected_ident); // missing selector name.
1286 SkipUntil(tok::semi);
1287 return 0;
1288 }
1289 if (Tok.getKind() != tok::r_square) {
1290 Diag(Tok, diag::err_expected_rsquare);
1291 SkipUntil(tok::semi);
1292 return 0;
1293 }
Steve Naroffc39ca262007-09-18 23:55:05 +00001294 SourceLocation RBracloc = ConsumeBracket(); // consume ']'
Steve Naroff253118b2007-09-17 20:25:27 +00001295
Steve Naroff4ed9d662007-09-27 14:38:14 +00001296 if (KeyIdents.size()) {
Steve Naroff6cb1d362007-09-28 22:22:11 +00001297 Selector sel = ObjcGetKeywordSelector(KeyIdents);
Steve Naroffd3f5ee42007-09-17 21:01:15 +00001298 // We've just parsed a keyword message.
1299 if (ReceiverName)
Steve Naroff6cb1d362007-09-28 22:22:11 +00001300 return Actions.ActOnClassMessage(ReceiverName, sel, LBracloc, RBracloc,
Steve Naroff4ed9d662007-09-27 14:38:14 +00001301 &KeyExprs[0]);
Steve Naroff6cb1d362007-09-28 22:22:11 +00001302 return Actions.ActOnInstanceMessage(ReceiverExpr, sel, LBracloc, RBracloc,
Steve Naroff4ed9d662007-09-27 14:38:14 +00001303 &KeyExprs[0]);
Steve Naroffd3f5ee42007-09-17 21:01:15 +00001304 }
Steve Naroff6cb1d362007-09-28 22:22:11 +00001305 Selector sel = ObjcGetUnarySelector(selIdent);
Steve Naroff4ed9d662007-09-27 14:38:14 +00001306
Steve Naroffd3f5ee42007-09-17 21:01:15 +00001307 // We've just parsed a unary message (a message with no arguments).
Steve Naroff253118b2007-09-17 20:25:27 +00001308 if (ReceiverName)
Steve Naroff6cb1d362007-09-28 22:22:11 +00001309 return Actions.ActOnClassMessage(ReceiverName, sel, LBracloc, RBracloc, 0);
1310 return Actions.ActOnInstanceMessage(ReceiverExpr, sel, LBracloc, RBracloc, 0);
Fariborz Jahanian1e534dc2007-09-05 19:52:07 +00001311}
1312
Anders Carlssona66cad42007-08-21 17:43:55 +00001313Parser::ExprResult Parser::ParseObjCStringLiteral() {
1314 ExprResult Res = ParseStringLiteralExpression();
1315
1316 if (Res.isInvalid) return Res;
1317
1318 return Actions.ParseObjCStringLiteral(Res.Val);
1319}
Anders Carlsson8be1d402007-08-22 15:14:15 +00001320
1321/// objc-encode-expression:
1322/// @encode ( type-name )
1323Parser::ExprResult Parser::ParseObjCEncodeExpression() {
Steve Naroff87c329f2007-08-23 18:16:40 +00001324 assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
Anders Carlsson8be1d402007-08-22 15:14:15 +00001325
1326 SourceLocation EncLoc = ConsumeToken();
1327
1328 if (Tok.getKind() != tok::l_paren) {
1329 Diag(Tok, diag::err_expected_lparen_after, "@encode");
1330 return true;
1331 }
1332
1333 SourceLocation LParenLoc = ConsumeParen();
1334
1335 TypeTy *Ty = ParseTypeName();
1336
Anders Carlsson92faeb82007-08-23 15:31:37 +00001337 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
Anders Carlsson8be1d402007-08-22 15:14:15 +00001338
1339 return Actions.ParseObjCEncodeExpression(EncLoc, LParenLoc, Ty,
Anders Carlsson92faeb82007-08-23 15:31:37 +00001340 RParenLoc);
Anders Carlsson8be1d402007-08-22 15:14:15 +00001341}
Anders Carlsson2996b4e2007-08-23 15:25:28 +00001342
1343/// objc-protocol-expression
1344/// @protocol ( protocol-name )
1345
1346Parser::ExprResult Parser::ParseObjCProtocolExpression()
1347{
1348 SourceLocation ProtoLoc = ConsumeToken();
1349
1350 if (Tok.getKind() != tok::l_paren) {
1351 Diag(Tok, diag::err_expected_lparen_after, "@protocol");
1352 return true;
1353 }
1354
1355 SourceLocation LParenLoc = ConsumeParen();
1356
1357 if (Tok.getKind() != tok::identifier) {
1358 Diag(Tok, diag::err_expected_ident);
1359 return true;
1360 }
1361
1362 // FIXME: Do something with the protocol name
1363 ConsumeToken();
1364
Anders Carlsson92faeb82007-08-23 15:31:37 +00001365 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
Anders Carlsson2996b4e2007-08-23 15:25:28 +00001366
1367 // FIXME
1368 return 0;
1369}