2008-01-08 03:49:32 +08:00
|
|
|
//===--- ParseObjC.cpp - Objective C Parsing ------------------------------===//
|
2006-11-05 10:08:13 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 03:59:25 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2006-11-05 10:08:13 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the Objective-C portions of the Parser interface.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/Parse/Parser.h"
|
2007-08-23 02:35:33 +08:00
|
|
|
#include "clang/Parse/DeclSpec.h"
|
2007-11-02 07:59:59 +08:00
|
|
|
#include "clang/Parse/Scope.h"
|
2008-11-26 06:21:31 +08:00
|
|
|
#include "AstGuard.h"
|
2009-01-29 13:15:15 +08:00
|
|
|
#include "clang/Parse/ParseDiagnostic.h"
|
2006-11-05 10:08:13 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
|
2008-12-09 05:53:24 +08:00
|
|
|
/// ParseObjCAtDirectives - Handle parts of the external-declaration production:
|
2006-11-05 10:08:13 +08:00
|
|
|
/// external-declaration: [C99 6.9]
|
|
|
|
/// [OBJC] objc-class-definition
|
2007-10-30 05:39:29 +08:00
|
|
|
/// [OBJC] objc-class-declaration
|
|
|
|
/// [OBJC] objc-alias-declaration
|
|
|
|
/// [OBJC] objc-protocol-definition
|
|
|
|
/// [OBJC] objc-method-definition
|
|
|
|
/// [OBJC] '@' 'end'
|
2007-08-21 05:31:48 +08:00
|
|
|
Parser::DeclTy *Parser::ParseObjCAtDirectives() {
|
2006-11-05 10:08:13 +08:00
|
|
|
SourceLocation AtLoc = ConsumeToken(); // the "@"
|
|
|
|
|
2007-08-24 02:16:40 +08:00
|
|
|
switch (Tok.getObjCKeywordID()) {
|
2008-08-23 10:02:23 +08:00
|
|
|
case tok::objc_class:
|
|
|
|
return ParseObjCAtClassDeclaration(AtLoc);
|
|
|
|
case tok::objc_interface:
|
|
|
|
return ParseObjCAtInterfaceDeclaration(AtLoc);
|
|
|
|
case tok::objc_protocol:
|
|
|
|
return ParseObjCAtProtocolDeclaration(AtLoc);
|
|
|
|
case tok::objc_implementation:
|
|
|
|
return ParseObjCAtImplementationDeclaration(AtLoc);
|
|
|
|
case tok::objc_end:
|
|
|
|
return ParseObjCAtEndDeclaration(AtLoc);
|
|
|
|
case tok::objc_compatibility_alias:
|
|
|
|
return ParseObjCAtAliasDeclaration(AtLoc);
|
|
|
|
case tok::objc_synthesize:
|
|
|
|
return ParseObjCPropertySynthesize(AtLoc);
|
|
|
|
case tok::objc_dynamic:
|
|
|
|
return ParseObjCPropertyDynamic(AtLoc);
|
|
|
|
default:
|
|
|
|
Diag(AtLoc, diag::err_unexpected_at);
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return 0;
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// objc-class-declaration:
|
|
|
|
/// '@' 'class' identifier-list ';'
|
|
|
|
///
|
2007-08-21 05:31:48 +08:00
|
|
|
Parser::DeclTy *Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
|
2006-11-05 10:08:13 +08:00
|
|
|
ConsumeToken(); // the identifier "class"
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::SmallVector<IdentifierInfo *, 8> ClassNames;
|
2006-11-05 10:08:13 +08:00
|
|
|
|
|
|
|
while (1) {
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2006-11-10 13:19:25 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident);
|
2006-11-05 10:08:13 +08:00
|
|
|
SkipUntil(tok::semi);
|
2007-08-21 05:31:48 +08:00
|
|
|
return 0;
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
|
|
|
ClassNames.push_back(Tok.getIdentifierInfo());
|
|
|
|
ConsumeToken();
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2006-11-05 10:08:13 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Consume the ';'.
|
|
|
|
if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
|
2007-08-21 05:31:48 +08:00
|
|
|
return 0;
|
2006-11-05 10:08:13 +08:00
|
|
|
|
2007-10-11 01:32:04 +08:00
|
|
|
return Actions.ActOnForwardClassDeclaration(atLoc,
|
2007-09-07 05:24:23 +08:00
|
|
|
&ClassNames[0], ClassNames.size());
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
///
|
|
|
|
/// objc-interface:
|
|
|
|
/// objc-class-interface-attributes[opt] objc-class-interface
|
|
|
|
/// objc-category-interface
|
|
|
|
///
|
|
|
|
/// objc-class-interface:
|
|
|
|
/// '@' 'interface' identifier objc-superclass[opt]
|
|
|
|
/// objc-protocol-refs[opt]
|
|
|
|
/// objc-class-instance-variables[opt]
|
|
|
|
/// objc-interface-decl-list
|
|
|
|
/// @end
|
|
|
|
///
|
|
|
|
/// objc-category-interface:
|
|
|
|
/// '@' 'interface' identifier '(' identifier[opt] ')'
|
|
|
|
/// objc-protocol-refs[opt]
|
|
|
|
/// objc-interface-decl-list
|
|
|
|
/// @end
|
|
|
|
///
|
|
|
|
/// objc-superclass:
|
|
|
|
/// ':' identifier
|
|
|
|
///
|
|
|
|
/// objc-class-interface-attributes:
|
|
|
|
/// __attribute__((visibility("default")))
|
|
|
|
/// __attribute__((visibility("hidden")))
|
|
|
|
/// __attribute__((deprecated))
|
|
|
|
/// __attribute__((unavailable))
|
|
|
|
/// __attribute__((objc_exception)) - used by NSException on 64-bit
|
|
|
|
///
|
|
|
|
Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration(
|
|
|
|
SourceLocation atLoc, AttributeList *attrList) {
|
2007-08-24 02:16:40 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
|
2007-08-21 05:31:48 +08:00
|
|
|
"ParseObjCAtInterfaceDeclaration(): Expected @interface");
|
|
|
|
ConsumeToken(); // the "interface" identifier
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-08-21 05:31:48 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident); // missing class or category name.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// We have a class or category name - consume it.
|
2007-08-23 06:17:26 +08:00
|
|
|
IdentifierInfo *nameId = Tok.getIdentifierInfo();
|
2007-08-21 05:31:48 +08:00
|
|
|
SourceLocation nameLoc = ConsumeToken();
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::l_paren)) { // we have a category.
|
2007-08-21 05:31:48 +08:00
|
|
|
SourceLocation lparenLoc = ConsumeParen();
|
|
|
|
SourceLocation categoryLoc, rparenLoc;
|
|
|
|
IdentifierInfo *categoryId = 0;
|
|
|
|
|
2007-08-24 03:56:30 +08:00
|
|
|
// For ObjC2, the category name is optional (not an error).
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
2007-08-21 05:31:48 +08:00
|
|
|
categoryId = Tok.getIdentifierInfo();
|
|
|
|
categoryLoc = ConsumeToken();
|
2007-08-24 03:56:30 +08:00
|
|
|
} else if (!getLang().ObjC2) {
|
|
|
|
Diag(Tok, diag::err_expected_ident); // missing category name.
|
|
|
|
return 0;
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2007-08-21 05:31:48 +08:00
|
|
|
Diag(Tok, diag::err_expected_rparen);
|
|
|
|
SkipUntil(tok::r_paren, false); // don't stop at ';'
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
rparenLoc = ConsumeParen();
|
2008-07-26 12:07:02 +08:00
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
// Next, we need to check for any protocol references.
|
2008-07-26 12:07:02 +08:00
|
|
|
SourceLocation EndProtoLoc;
|
|
|
|
llvm::SmallVector<DeclTy *, 8> ProtocolRefs;
|
|
|
|
if (Tok.is(tok::less) &&
|
|
|
|
ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc))
|
|
|
|
return 0;
|
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
if (attrList) // categories don't support attributes.
|
|
|
|
Diag(Tok, diag::err_objc_no_attributes_on_category);
|
|
|
|
|
2007-10-11 01:32:04 +08:00
|
|
|
DeclTy *CategoryType = Actions.ActOnStartCategoryInterface(atLoc,
|
2007-10-04 05:00:46 +08:00
|
|
|
nameId, nameLoc, categoryId, categoryLoc,
|
2007-10-30 21:30:57 +08:00
|
|
|
&ProtocolRefs[0], ProtocolRefs.size(),
|
2008-07-26 12:07:02 +08:00
|
|
|
EndProtoLoc);
|
2007-09-19 04:26:58 +08:00
|
|
|
|
|
|
|
ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword);
|
2008-10-20 14:10:06 +08:00
|
|
|
return CategoryType;
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
|
|
|
// Parse a class interface.
|
|
|
|
IdentifierInfo *superClassId = 0;
|
|
|
|
SourceLocation superClassLoc;
|
2007-08-23 06:17:26 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::colon)) { // a super class is specified.
|
2007-08-21 05:31:48 +08:00
|
|
|
ConsumeToken();
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-08-21 05:31:48 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident); // missing super class name.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
superClassId = Tok.getIdentifierInfo();
|
|
|
|
superClassLoc = ConsumeToken();
|
|
|
|
}
|
|
|
|
// Next, we need to check for any protocol references.
|
2008-07-26 12:13:19 +08:00
|
|
|
llvm::SmallVector<Action::DeclTy*, 8> ProtocolRefs;
|
|
|
|
SourceLocation EndProtoLoc;
|
|
|
|
if (Tok.is(tok::less) &&
|
|
|
|
ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
DeclTy *ClsType =
|
|
|
|
Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc,
|
|
|
|
superClassId, superClassLoc,
|
|
|
|
&ProtocolRefs[0], ProtocolRefs.size(),
|
|
|
|
EndProtoLoc, attrList);
|
2007-09-06 07:30:30 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
2007-10-30 05:38:07 +08:00
|
|
|
ParseObjCClassInstanceVariables(ClsType, atLoc);
|
2007-08-21 05:31:48 +08:00
|
|
|
|
2007-09-18 05:07:36 +08:00
|
|
|
ParseObjCInterfaceDeclList(ClsType, tok::objc_interface);
|
2008-10-20 14:10:06 +08:00
|
|
|
return ClsType;
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// objc-interface-decl-list:
|
|
|
|
/// empty
|
|
|
|
/// objc-interface-decl-list objc-property-decl [OBJC2]
|
2007-08-23 00:35:03 +08:00
|
|
|
/// objc-interface-decl-list objc-method-requirement [OBJC2]
|
2007-09-07 05:24:23 +08:00
|
|
|
/// objc-interface-decl-list objc-method-proto ';'
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-interface-decl-list declaration
|
|
|
|
/// objc-interface-decl-list ';'
|
|
|
|
///
|
2007-08-23 00:35:03 +08:00
|
|
|
/// objc-method-requirement: [OBJC2]
|
|
|
|
/// @required
|
|
|
|
/// @optional
|
|
|
|
///
|
2007-09-18 05:07:36 +08:00
|
|
|
void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl,
|
2007-12-28 03:57:00 +08:00
|
|
|
tok::ObjCKeywordKind contextKey) {
|
2008-06-07 00:45:15 +08:00
|
|
|
llvm::SmallVector<DeclTy*, 32> allMethods;
|
2007-11-07 06:01:00 +08:00
|
|
|
llvm::SmallVector<DeclTy*, 16> allProperties;
|
2007-09-18 08:25:23 +08:00
|
|
|
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
|
2007-10-30 05:38:07 +08:00
|
|
|
|
2008-10-20 14:10:06 +08:00
|
|
|
SourceLocation AtEndLoc;
|
|
|
|
|
2007-08-23 00:35:03 +08:00
|
|
|
while (1) {
|
2008-10-20 13:46:22 +08:00
|
|
|
// If this is a method prototype, parse it.
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::minus) || Tok.is(tok::plus)) {
|
|
|
|
DeclTy *methodPrototype =
|
|
|
|
ParseObjCMethodPrototype(interfaceDecl, MethodImplKind);
|
2007-09-18 05:07:36 +08:00
|
|
|
allMethods.push_back(methodPrototype);
|
2007-09-07 05:24:23 +08:00
|
|
|
// Consume the ';' here, since ParseObjCMethodPrototype() is re-used for
|
|
|
|
// method definitions.
|
2009-02-16 06:24:30 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_method_proto,
|
|
|
|
"", tok::semi);
|
2007-08-23 00:35:03 +08:00
|
|
|
continue;
|
|
|
|
}
|
2007-12-12 02:34:51 +08:00
|
|
|
|
2008-10-20 13:46:22 +08:00
|
|
|
// Ignore excess semicolons.
|
|
|
|
if (Tok.is(tok::semi)) {
|
2007-08-23 00:35:03 +08:00
|
|
|
ConsumeToken();
|
2008-10-20 13:46:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-10-20 14:10:06 +08:00
|
|
|
// If we got to the end of the file, exit the loop.
|
2008-10-20 13:46:22 +08:00
|
|
|
if (Tok.is(tok::eof))
|
2007-09-11 04:33:04 +08:00
|
|
|
break;
|
2008-10-20 13:46:22 +08:00
|
|
|
|
|
|
|
// If we don't have an @ directive, parse it as a function definition.
|
|
|
|
if (Tok.isNot(tok::at)) {
|
2009-01-09 12:34:13 +08:00
|
|
|
// The code below does not consume '}'s because it is afraid of eating the
|
|
|
|
// end of a namespace. Because of the way this code is structured, an
|
|
|
|
// erroneous r_brace would cause an infinite loop if not handled here.
|
|
|
|
if (Tok.is(tok::r_brace))
|
|
|
|
break;
|
|
|
|
|
2007-08-23 02:35:33 +08:00
|
|
|
// FIXME: as the name implies, this rule allows function definitions.
|
|
|
|
// We could pass a flag or check for functions during semantic analysis.
|
2007-09-07 05:24:23 +08:00
|
|
|
ParseDeclarationOrFunctionDefinition();
|
2008-10-20 13:46:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we have an @ directive, eat the @.
|
|
|
|
SourceLocation AtLoc = ConsumeToken(); // the "@"
|
2008-10-20 13:57:40 +08:00
|
|
|
tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
|
2008-10-20 13:46:22 +08:00
|
|
|
|
2008-10-20 13:57:40 +08:00
|
|
|
if (DirectiveKind == tok::objc_end) { // @end -> terminate list
|
2008-10-20 13:46:22 +08:00
|
|
|
AtEndLoc = AtLoc;
|
|
|
|
break;
|
2008-10-20 14:10:06 +08:00
|
|
|
}
|
2008-10-20 13:46:22 +08:00
|
|
|
|
2008-10-20 14:10:06 +08:00
|
|
|
// Eat the identifier.
|
|
|
|
ConsumeToken();
|
|
|
|
|
2008-10-20 13:57:40 +08:00
|
|
|
switch (DirectiveKind) {
|
|
|
|
default:
|
2008-10-20 14:10:06 +08:00
|
|
|
// FIXME: If someone forgets an @end on a protocol, this loop will
|
|
|
|
// continue to eat up tons of stuff and spew lots of nonsense errors. It
|
|
|
|
// would probably be better to bail out if we saw an @class or @interface
|
|
|
|
// or something like that.
|
2008-10-20 15:22:18 +08:00
|
|
|
Diag(AtLoc, diag::err_objc_illegal_interface_qual);
|
2008-10-20 14:10:06 +08:00
|
|
|
// Skip until we see an '@' or '}' or ';'.
|
2008-10-20 13:57:40 +08:00
|
|
|
SkipUntil(tok::r_brace, tok::at);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::objc_required:
|
|
|
|
case tok::objc_optional:
|
|
|
|
// This is only valid on protocols.
|
2008-10-20 14:10:06 +08:00
|
|
|
// FIXME: Should this check for ObjC2 being enabled?
|
2008-10-20 13:46:22 +08:00
|
|
|
if (contextKey != tok::objc_protocol)
|
2008-10-20 14:10:06 +08:00
|
|
|
Diag(AtLoc, diag::err_objc_directive_only_in_protocol);
|
2008-10-20 13:57:40 +08:00
|
|
|
else
|
2008-10-20 14:10:06 +08:00
|
|
|
MethodImplKind = DirectiveKind;
|
2008-10-20 13:57:40 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::objc_property:
|
2008-10-20 15:22:18 +08:00
|
|
|
if (!getLang().ObjC2)
|
|
|
|
Diag(AtLoc, diag::err_objc_propertoes_require_objc2);
|
|
|
|
|
2008-10-20 13:46:22 +08:00
|
|
|
ObjCDeclSpec OCDS;
|
|
|
|
// Parse property attribute list, if any.
|
2008-10-20 15:24:39 +08:00
|
|
|
if (Tok.is(tok::l_paren))
|
2008-10-20 13:46:22 +08:00
|
|
|
ParseObjCPropertyAttribute(OCDS);
|
2008-10-20 15:00:43 +08:00
|
|
|
|
2008-10-20 13:46:22 +08:00
|
|
|
// Parse all the comma separated declarators.
|
|
|
|
DeclSpec DS;
|
|
|
|
llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators;
|
|
|
|
ParseStructDeclaration(DS, FieldDeclarators);
|
|
|
|
|
2008-10-20 14:15:13 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list, "",
|
|
|
|
tok::at);
|
|
|
|
|
2008-10-20 13:46:22 +08:00
|
|
|
// Convert them all to property declarations.
|
|
|
|
for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) {
|
|
|
|
FieldDeclarator &FD = FieldDeclarators[i];
|
2008-10-20 14:33:53 +08:00
|
|
|
if (FD.D.getIdentifier() == 0) {
|
2008-11-18 15:50:21 +08:00
|
|
|
Diag(AtLoc, diag::err_objc_property_requires_field_name)
|
|
|
|
<< FD.D.getSourceRange();
|
2008-10-20 14:33:53 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-01-18 07:21:10 +08:00
|
|
|
if (FD.BitfieldSize) {
|
|
|
|
Diag(AtLoc, diag::err_objc_property_bitfield)
|
|
|
|
<< FD.D.getSourceRange();
|
|
|
|
continue;
|
|
|
|
}
|
2008-10-20 14:33:53 +08:00
|
|
|
|
2008-10-20 13:46:22 +08:00
|
|
|
// Install the property declarator into interfaceDecl.
|
2008-10-20 14:33:53 +08:00
|
|
|
IdentifierInfo *SelName =
|
|
|
|
OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
|
|
|
|
|
2008-10-20 13:46:22 +08:00
|
|
|
Selector GetterSel =
|
2008-10-20 14:33:53 +08:00
|
|
|
PP.getSelectorTable().getNullarySelector(SelName);
|
2008-10-20 13:46:22 +08:00
|
|
|
IdentifierInfo *SetterName = OCDS.getSetterName();
|
2009-03-13 06:34:11 +08:00
|
|
|
Selector SetterSel;
|
|
|
|
if (SetterName)
|
|
|
|
SetterSel = PP.getSelectorTable().getSelector(1, &SetterName);
|
|
|
|
else
|
|
|
|
SetterSel = SelectorTable::constructSetterName(PP.getIdentifierTable(),
|
|
|
|
PP.getSelectorTable(),
|
|
|
|
FD.D.getIdentifier());
|
2008-11-27 04:01:34 +08:00
|
|
|
bool isOverridingProperty = false;
|
2008-10-20 14:33:53 +08:00
|
|
|
DeclTy *Property = Actions.ActOnProperty(CurScope, AtLoc, FD, OCDS,
|
|
|
|
GetterSel, SetterSel,
|
2008-11-27 04:01:34 +08:00
|
|
|
interfaceDecl,
|
|
|
|
&isOverridingProperty,
|
2008-10-20 14:33:53 +08:00
|
|
|
MethodImplKind);
|
2008-11-27 04:01:34 +08:00
|
|
|
if (!isOverridingProperty)
|
|
|
|
allProperties.push_back(Property);
|
2008-10-20 13:46:22 +08:00
|
|
|
}
|
2008-10-20 13:57:40 +08:00
|
|
|
break;
|
2007-09-06 07:30:30 +08:00
|
|
|
}
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
2008-10-20 14:10:06 +08:00
|
|
|
|
|
|
|
// We break out of the big loop in two cases: when we see @end or when we see
|
|
|
|
// EOF. In the former case, eat the @end. In the later case, emit an error.
|
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_end))
|
|
|
|
ConsumeToken(); // the "end" identifier
|
|
|
|
else
|
|
|
|
Diag(Tok, diag::err_objc_missing_end);
|
|
|
|
|
2008-10-20 13:57:40 +08:00
|
|
|
// Insert collected methods declarations into the @interface object.
|
2008-10-20 14:10:06 +08:00
|
|
|
// This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
|
2008-06-07 00:45:15 +08:00
|
|
|
Actions.ActOnAtEnd(AtEndLoc, interfaceDecl,
|
|
|
|
allMethods.empty() ? 0 : &allMethods[0],
|
|
|
|
allMethods.size(),
|
|
|
|
allProperties.empty() ? 0 : &allProperties[0],
|
|
|
|
allProperties.size());
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
2007-09-01 00:11:31 +08:00
|
|
|
/// Parse property attribute declarations.
|
|
|
|
///
|
|
|
|
/// property-attr-decl: '(' property-attrlist ')'
|
|
|
|
/// property-attrlist:
|
|
|
|
/// property-attribute
|
|
|
|
/// property-attrlist ',' property-attribute
|
|
|
|
/// property-attribute:
|
|
|
|
/// getter '=' identifier
|
|
|
|
/// setter '=' identifier ':'
|
|
|
|
/// readonly
|
|
|
|
/// readwrite
|
|
|
|
/// assign
|
|
|
|
/// retain
|
|
|
|
/// copy
|
|
|
|
/// nonatomic
|
|
|
|
///
|
2008-07-22 06:17:28 +08:00
|
|
|
void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
|
2008-10-20 15:24:39 +08:00
|
|
|
assert(Tok.getKind() == tok::l_paren);
|
2008-10-20 15:00:43 +08:00
|
|
|
SourceLocation LHSLoc = ConsumeParen(); // consume '('
|
|
|
|
|
2008-10-20 15:15:22 +08:00
|
|
|
while (1) {
|
2007-09-01 00:11:31 +08:00
|
|
|
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
2008-10-20 15:22:18 +08:00
|
|
|
|
|
|
|
// If this is not an identifier at all, bail out early.
|
|
|
|
if (II == 0) {
|
|
|
|
MatchRHSPunctuation(tok::r_paren, LHSLoc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-10-20 15:37:22 +08:00
|
|
|
SourceLocation AttrName = ConsumeToken(); // consume last attribute name
|
|
|
|
|
2008-11-20 12:42:34 +08:00
|
|
|
if (II->isStr("readonly"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readonly);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("assign"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_assign);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("readwrite"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readwrite);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("retain"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_retain);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("copy"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("nonatomic"))
|
2008-10-20 15:39:53 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic);
|
2008-11-20 12:42:34 +08:00
|
|
|
else if (II->isStr("getter") || II->isStr("setter")) {
|
2008-10-20 15:39:53 +08:00
|
|
|
// getter/setter require extra treatment.
|
2008-10-20 15:37:22 +08:00
|
|
|
if (ExpectAndConsume(tok::equal, diag::err_objc_expected_equal, "",
|
|
|
|
tok::r_paren))
|
2008-10-20 15:00:43 +08:00
|
|
|
return;
|
2008-10-20 15:37:22 +08:00
|
|
|
|
2008-10-20 15:24:39 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident);
|
2008-10-20 15:24:39 +08:00
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-10-20 15:43:01 +08:00
|
|
|
if (II->getName()[0] == 's') {
|
2008-10-20 15:24:39 +08:00
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter);
|
|
|
|
DS.setSetterName(Tok.getIdentifierInfo());
|
2008-10-20 15:37:22 +08:00
|
|
|
ConsumeToken(); // consume method name
|
|
|
|
|
|
|
|
if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "",
|
|
|
|
tok::r_paren))
|
2008-10-20 15:24:39 +08:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter);
|
|
|
|
DS.setGetterName(Tok.getIdentifierInfo());
|
2008-10-20 15:37:22 +08:00
|
|
|
ConsumeToken(); // consume method name
|
2008-10-20 15:24:39 +08:00
|
|
|
}
|
2008-10-20 15:39:53 +08:00
|
|
|
} else {
|
2008-11-19 15:49:38 +08:00
|
|
|
Diag(AttrName, diag::err_objc_expected_property_attr) << II;
|
2008-10-20 15:15:22 +08:00
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
return;
|
|
|
|
}
|
2007-11-07 06:01:00 +08:00
|
|
|
|
2008-10-20 15:37:22 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
|
|
|
break;
|
2008-10-20 15:00:43 +08:00
|
|
|
|
2008-10-20 15:37:22 +08:00
|
|
|
ConsumeToken();
|
2007-09-01 00:11:31 +08:00
|
|
|
}
|
2008-10-20 15:37:22 +08:00
|
|
|
|
|
|
|
MatchRHSPunctuation(tok::r_paren, LHSLoc);
|
2007-09-01 00:11:31 +08:00
|
|
|
}
|
|
|
|
|
2007-09-07 05:24:23 +08:00
|
|
|
/// objc-method-proto:
|
2007-09-01 08:26:16 +08:00
|
|
|
/// objc-instance-method objc-method-decl objc-method-attributes[opt]
|
2007-09-07 05:24:23 +08:00
|
|
|
/// objc-class-method objc-method-decl objc-method-attributes[opt]
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
|
|
|
/// objc-instance-method: '-'
|
|
|
|
/// objc-class-method: '+'
|
|
|
|
///
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-method-attributes: [OBJC2]
|
|
|
|
/// __attribute__((deprecated))
|
|
|
|
///
|
2007-09-18 08:25:23 +08:00
|
|
|
Parser::DeclTy *Parser::ParseObjCMethodPrototype(DeclTy *IDecl,
|
2007-12-28 03:57:00 +08:00
|
|
|
tok::ObjCKeywordKind MethodImplKind) {
|
2007-10-10 01:51:17 +08:00
|
|
|
assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-");
|
2007-08-23 00:35:03 +08:00
|
|
|
|
|
|
|
tok::TokenKind methodType = Tok.getKind();
|
2007-10-27 04:53:56 +08:00
|
|
|
SourceLocation mLoc = ConsumeToken();
|
2007-08-23 00:35:03 +08:00
|
|
|
|
2007-11-10 03:52:12 +08:00
|
|
|
DeclTy *MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl, MethodImplKind);
|
2007-09-07 05:24:23 +08:00
|
|
|
// Since this rule is used for both method declarations and definitions,
|
2007-09-11 04:51:04 +08:00
|
|
|
// the caller is (optionally) responsible for consuming the ';'.
|
2007-09-06 07:30:30 +08:00
|
|
|
return MDecl;
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// objc-selector:
|
|
|
|
/// identifier
|
|
|
|
/// one of
|
|
|
|
/// enum struct union if else while do for switch case default
|
|
|
|
/// break continue return goto asm sizeof typeof __alignof
|
|
|
|
/// unsigned long const short volatile signed restrict _Complex
|
|
|
|
/// in out inout bycopy byref oneway int char float double void _Bool
|
|
|
|
///
|
2007-10-11 08:55:41 +08:00
|
|
|
IdentifierInfo *Parser::ParseObjCSelector(SourceLocation &SelectorLoc) {
|
2007-10-07 10:00:24 +08:00
|
|
|
switch (Tok.getKind()) {
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
case tok::identifier:
|
2008-08-24 05:00:01 +08:00
|
|
|
case tok::kw_asm:
|
2007-10-07 10:00:24 +08:00
|
|
|
case tok::kw_auto:
|
2007-11-15 13:25:19 +08:00
|
|
|
case tok::kw_bool:
|
2008-08-24 05:00:01 +08:00
|
|
|
case tok::kw_break:
|
|
|
|
case tok::kw_case:
|
|
|
|
case tok::kw_catch:
|
|
|
|
case tok::kw_char:
|
|
|
|
case tok::kw_class:
|
|
|
|
case tok::kw_const:
|
|
|
|
case tok::kw_const_cast:
|
|
|
|
case tok::kw_continue:
|
|
|
|
case tok::kw_default:
|
|
|
|
case tok::kw_delete:
|
|
|
|
case tok::kw_do:
|
|
|
|
case tok::kw_double:
|
|
|
|
case tok::kw_dynamic_cast:
|
|
|
|
case tok::kw_else:
|
|
|
|
case tok::kw_enum:
|
|
|
|
case tok::kw_explicit:
|
|
|
|
case tok::kw_export:
|
|
|
|
case tok::kw_extern:
|
|
|
|
case tok::kw_false:
|
|
|
|
case tok::kw_float:
|
|
|
|
case tok::kw_for:
|
|
|
|
case tok::kw_friend:
|
|
|
|
case tok::kw_goto:
|
|
|
|
case tok::kw_if:
|
|
|
|
case tok::kw_inline:
|
|
|
|
case tok::kw_int:
|
|
|
|
case tok::kw_long:
|
|
|
|
case tok::kw_mutable:
|
|
|
|
case tok::kw_namespace:
|
|
|
|
case tok::kw_new:
|
|
|
|
case tok::kw_operator:
|
|
|
|
case tok::kw_private:
|
|
|
|
case tok::kw_protected:
|
|
|
|
case tok::kw_public:
|
|
|
|
case tok::kw_register:
|
|
|
|
case tok::kw_reinterpret_cast:
|
|
|
|
case tok::kw_restrict:
|
|
|
|
case tok::kw_return:
|
|
|
|
case tok::kw_short:
|
|
|
|
case tok::kw_signed:
|
|
|
|
case tok::kw_sizeof:
|
|
|
|
case tok::kw_static:
|
|
|
|
case tok::kw_static_cast:
|
|
|
|
case tok::kw_struct:
|
|
|
|
case tok::kw_switch:
|
|
|
|
case tok::kw_template:
|
|
|
|
case tok::kw_this:
|
|
|
|
case tok::kw_throw:
|
|
|
|
case tok::kw_true:
|
|
|
|
case tok::kw_try:
|
|
|
|
case tok::kw_typedef:
|
|
|
|
case tok::kw_typeid:
|
|
|
|
case tok::kw_typename:
|
|
|
|
case tok::kw_typeof:
|
|
|
|
case tok::kw_union:
|
|
|
|
case tok::kw_unsigned:
|
|
|
|
case tok::kw_using:
|
|
|
|
case tok::kw_virtual:
|
|
|
|
case tok::kw_void:
|
|
|
|
case tok::kw_volatile:
|
|
|
|
case tok::kw_wchar_t:
|
|
|
|
case tok::kw_while:
|
2007-10-07 10:00:24 +08:00
|
|
|
case tok::kw__Bool:
|
|
|
|
case tok::kw__Complex:
|
2008-08-24 05:00:01 +08:00
|
|
|
case tok::kw___alignof:
|
2007-10-07 10:00:24 +08:00
|
|
|
IdentifierInfo *II = Tok.getIdentifierInfo();
|
2007-10-11 08:55:41 +08:00
|
|
|
SelectorLoc = ConsumeToken();
|
2007-10-07 10:00:24 +08:00
|
|
|
return II;
|
2007-09-28 03:52:15 +08:00
|
|
|
}
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
2008-01-03 06:54:34 +08:00
|
|
|
/// objc-for-collection-in: 'in'
|
|
|
|
///
|
2008-01-05 07:04:08 +08:00
|
|
|
bool Parser::isTokIdentifier_in() const {
|
2008-01-04 01:55:25 +08:00
|
|
|
// FIXME: May have to do additional look-ahead to only allow for
|
|
|
|
// valid tokens following an 'in'; such as an identifier, unary operators,
|
|
|
|
// '[' etc.
|
2008-01-05 07:04:08 +08:00
|
|
|
return (getLang().ObjC2 && Tok.is(tok::identifier) &&
|
2008-08-23 10:02:23 +08:00
|
|
|
Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]);
|
2008-01-03 06:54:34 +08:00
|
|
|
}
|
|
|
|
|
2008-01-08 03:49:32 +08:00
|
|
|
/// ParseObjCTypeQualifierList - This routine parses the objective-c's type
|
2007-12-12 14:56:32 +08:00
|
|
|
/// qualifier list and builds their bitmask representation in the input
|
|
|
|
/// argument.
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
|
|
|
/// objc-type-qualifiers:
|
|
|
|
/// objc-type-qualifier
|
|
|
|
/// objc-type-qualifiers objc-type-qualifier
|
|
|
|
///
|
2008-01-08 03:49:32 +08:00
|
|
|
void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) {
|
2007-12-12 14:56:32 +08:00
|
|
|
while (1) {
|
2007-12-28 03:57:00 +08:00
|
|
|
if (Tok.isNot(tok::identifier))
|
2007-12-12 14:56:32 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
|
|
|
for (unsigned i = 0; i != objc_NumQuals; ++i) {
|
2008-01-08 03:49:32 +08:00
|
|
|
if (II != ObjCTypeQuals[i])
|
2007-12-12 14:56:32 +08:00
|
|
|
continue;
|
|
|
|
|
2008-01-08 03:49:32 +08:00
|
|
|
ObjCDeclSpec::ObjCDeclQualifier Qual;
|
2007-12-12 14:56:32 +08:00
|
|
|
switch (i) {
|
|
|
|
default: assert(0 && "Unknown decl qualifier");
|
2008-01-08 03:49:32 +08:00
|
|
|
case objc_in: Qual = ObjCDeclSpec::DQ_In; break;
|
|
|
|
case objc_out: Qual = ObjCDeclSpec::DQ_Out; break;
|
|
|
|
case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break;
|
|
|
|
case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break;
|
|
|
|
case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break;
|
|
|
|
case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break;
|
2007-12-12 14:56:32 +08:00
|
|
|
}
|
2008-01-08 03:49:32 +08:00
|
|
|
DS.setObjCDeclQualifier(Qual);
|
2007-12-12 14:56:32 +08:00
|
|
|
ConsumeToken();
|
|
|
|
II = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this wasn't a recognized qualifier, bail out.
|
|
|
|
if (II) return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// objc-type-name:
|
|
|
|
/// '(' objc-type-qualifiers[opt] type-name ')'
|
|
|
|
/// '(' objc-type-qualifiers[opt] ')'
|
|
|
|
///
|
2008-01-08 03:49:32 +08:00
|
|
|
Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) {
|
2007-10-10 01:51:17 +08:00
|
|
|
assert(Tok.is(tok::l_paren) && "expected (");
|
2007-08-23 00:35:03 +08:00
|
|
|
|
2008-10-22 11:52:06 +08:00
|
|
|
SourceLocation LParenLoc = ConsumeParen();
|
2008-08-23 09:48:03 +08:00
|
|
|
SourceLocation TypeStartLoc = Tok.getLocation();
|
2007-08-23 00:35:03 +08:00
|
|
|
|
2007-11-01 05:59:43 +08:00
|
|
|
// Parse type qualifiers, in, inout, etc.
|
2008-01-08 03:49:32 +08:00
|
|
|
ParseObjCTypeQualifierList(DS);
|
2007-08-23 07:18:22 +08:00
|
|
|
|
2008-10-22 11:52:06 +08:00
|
|
|
TypeTy *Ty = 0;
|
2009-02-19 01:45:20 +08:00
|
|
|
if (isTypeSpecifierQualifier()) {
|
|
|
|
TypeResult TypeSpec = ParseTypeName();
|
|
|
|
if (!TypeSpec.isInvalid())
|
|
|
|
Ty = TypeSpec.get();
|
|
|
|
}
|
2008-08-23 09:48:03 +08:00
|
|
|
|
2008-10-22 11:52:06 +08:00
|
|
|
if (Tok.is(tok::r_paren))
|
|
|
|
ConsumeParen();
|
|
|
|
else if (Tok.getLocation() == TypeStartLoc) {
|
2008-08-23 09:48:03 +08:00
|
|
|
// If we didn't eat any tokens, then this isn't a type.
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_type);
|
2008-10-22 11:52:06 +08:00
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
} else {
|
|
|
|
// Otherwise, we found *something*, but didn't get a ')' in the right
|
|
|
|
// place. Emit an error then return what we have as the type.
|
|
|
|
MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
2007-09-06 07:30:30 +08:00
|
|
|
return Ty;
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// objc-method-decl:
|
|
|
|
/// objc-selector
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-keyword-selector objc-parmlist[opt]
|
2007-08-23 00:35:03 +08:00
|
|
|
/// objc-type-name objc-selector
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-type-name objc-keyword-selector objc-parmlist[opt]
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
|
|
|
/// objc-keyword-selector:
|
2007-08-23 06:17:26 +08:00
|
|
|
/// objc-keyword-decl
|
2007-08-23 00:35:03 +08:00
|
|
|
/// objc-keyword-selector objc-keyword-decl
|
|
|
|
///
|
|
|
|
/// objc-keyword-decl:
|
2007-08-23 06:17:26 +08:00
|
|
|
/// objc-selector ':' objc-type-name objc-keyword-attributes[opt] identifier
|
|
|
|
/// objc-selector ':' objc-keyword-attributes[opt] identifier
|
|
|
|
/// ':' objc-type-name objc-keyword-attributes[opt] identifier
|
|
|
|
/// ':' objc-keyword-attributes[opt] identifier
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-parmlist:
|
|
|
|
/// objc-parms objc-ellipsis[opt]
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-parms:
|
|
|
|
/// objc-parms , parameter-declaration
|
2007-08-23 00:35:03 +08:00
|
|
|
///
|
2007-08-23 02:35:33 +08:00
|
|
|
/// objc-ellipsis:
|
2007-08-23 00:35:03 +08:00
|
|
|
/// , ...
|
|
|
|
///
|
2007-08-23 06:17:26 +08:00
|
|
|
/// objc-keyword-attributes: [OBJC2]
|
|
|
|
/// __attribute__((unused))
|
|
|
|
///
|
2007-10-27 04:53:56 +08:00
|
|
|
Parser::DeclTy *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
|
2007-11-10 03:52:12 +08:00
|
|
|
tok::TokenKind mType,
|
|
|
|
DeclTy *IDecl,
|
2007-12-28 03:57:00 +08:00
|
|
|
tok::ObjCKeywordKind MethodImplKind)
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
{
|
2008-08-23 09:48:03 +08:00
|
|
|
// Parse the return type if present.
|
2007-10-07 10:00:24 +08:00
|
|
|
TypeTy *ReturnType = 0;
|
2008-01-08 03:49:32 +08:00
|
|
|
ObjCDeclSpec DSRet;
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::l_paren))
|
2007-11-01 07:53:01 +08:00
|
|
|
ReturnType = ParseObjCTypeName(DSRet);
|
2008-08-23 09:48:03 +08:00
|
|
|
|
2007-10-27 04:53:56 +08:00
|
|
|
SourceLocation selLoc;
|
|
|
|
IdentifierInfo *SelIdent = ParseObjCSelector(selLoc);
|
2008-08-23 09:48:03 +08:00
|
|
|
|
2009-02-12 04:43:13 +08:00
|
|
|
// An unnamed colon is valid.
|
|
|
|
if (!SelIdent && Tok.isNot(tok::colon)) { // missing selector name.
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_selector_for_method)
|
|
|
|
<< SourceRange(mLoc, Tok.getLocation());
|
2008-08-23 09:48:03 +08:00
|
|
|
// Skip until we get a ; or {}.
|
|
|
|
SkipUntil(tok::r_brace);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-01-09 08:38:19 +08:00
|
|
|
llvm::SmallVector<Declarator, 8> CargNames;
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::colon)) {
|
2007-10-07 10:00:24 +08:00
|
|
|
// If attributes exist after the method, parse them.
|
|
|
|
AttributeList *MethodAttrs = 0;
|
2007-10-10 01:51:17 +08:00
|
|
|
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
|
2007-10-07 10:00:24 +08:00
|
|
|
MethodAttrs = ParseAttributes();
|
|
|
|
|
|
|
|
Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
|
2007-10-27 04:53:56 +08:00
|
|
|
return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
|
2007-11-10 03:52:12 +08:00
|
|
|
mType, IDecl, DSRet, ReturnType, Sel,
|
2009-01-09 08:38:19 +08:00
|
|
|
0, 0, 0, CargNames,
|
|
|
|
MethodAttrs, MethodImplKind);
|
2007-10-07 10:00:24 +08:00
|
|
|
}
|
2007-09-06 07:30:30 +08:00
|
|
|
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
|
|
|
|
llvm::SmallVector<Action::TypeTy *, 12> KeyTypes;
|
2008-01-08 03:49:32 +08:00
|
|
|
llvm::SmallVector<ObjCDeclSpec, 12> ArgTypeQuals;
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
llvm::SmallVector<IdentifierInfo *, 12> ArgNames;
|
2007-10-07 10:00:24 +08:00
|
|
|
|
|
|
|
Action::TypeTy *TypeInfo;
|
|
|
|
while (1) {
|
|
|
|
KeyIdents.push_back(SelIdent);
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
// Each iteration parses a single keyword argument.
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::colon)) {
|
2007-10-07 10:00:24 +08:00
|
|
|
Diag(Tok, diag::err_expected_colon);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ConsumeToken(); // Eat the ':'.
|
2008-01-08 03:49:32 +08:00
|
|
|
ObjCDeclSpec DSType;
|
2008-08-23 09:48:03 +08:00
|
|
|
if (Tok.is(tok::l_paren)) // Parse the argument type.
|
2007-11-01 07:53:01 +08:00
|
|
|
TypeInfo = ParseObjCTypeName(DSType);
|
2007-10-07 10:00:24 +08:00
|
|
|
else
|
|
|
|
TypeInfo = 0;
|
|
|
|
KeyTypes.push_back(TypeInfo);
|
2007-11-01 07:53:01 +08:00
|
|
|
ArgTypeQuals.push_back(DSType);
|
2007-09-06 07:30:30 +08:00
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
// If attributes exist before the argument name, parse them.
|
2007-10-10 01:51:17 +08:00
|
|
|
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
|
2007-10-07 10:00:24 +08:00
|
|
|
ParseAttributes(); // FIXME: pass attributes through.
|
2007-08-23 06:17:26 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-10-07 10:00:24 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident); // missing argument name.
|
|
|
|
break;
|
2007-08-23 02:35:33 +08:00
|
|
|
}
|
2007-10-07 10:00:24 +08:00
|
|
|
ArgNames.push_back(Tok.getIdentifierInfo());
|
|
|
|
ConsumeToken(); // Eat the identifier.
|
|
|
|
|
|
|
|
// Check for another keyword selector.
|
2007-10-11 08:55:41 +08:00
|
|
|
SourceLocation Loc;
|
|
|
|
SelIdent = ParseObjCSelector(Loc);
|
2007-10-10 01:51:17 +08:00
|
|
|
if (!SelIdent && Tok.isNot(tok::colon))
|
2007-10-07 10:00:24 +08:00
|
|
|
break;
|
|
|
|
// We have a selector or a colon, continue parsing.
|
|
|
|
}
|
|
|
|
|
2007-11-15 20:35:21 +08:00
|
|
|
bool isVariadic = false;
|
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
// Parse the (optional) parameter list.
|
2007-10-10 01:51:17 +08:00
|
|
|
while (Tok.is(tok::comma)) {
|
2007-10-07 10:00:24 +08:00
|
|
|
ConsumeToken();
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::ellipsis)) {
|
2007-11-15 20:35:21 +08:00
|
|
|
isVariadic = true;
|
2007-08-23 02:35:33 +08:00
|
|
|
ConsumeToken();
|
2007-10-07 10:00:24 +08:00
|
|
|
break;
|
2007-08-23 02:35:33 +08:00
|
|
|
}
|
2007-10-07 10:00:24 +08:00
|
|
|
DeclSpec DS;
|
|
|
|
ParseDeclarationSpecifiers(DS);
|
|
|
|
// Parse the declarator.
|
|
|
|
Declarator ParmDecl(DS, Declarator::PrototypeContext);
|
|
|
|
ParseDeclarator(ParmDecl);
|
2009-01-09 08:38:19 +08:00
|
|
|
CargNames.push_back(ParmDecl);
|
2007-08-23 02:35:33 +08:00
|
|
|
}
|
2007-10-07 10:00:24 +08:00
|
|
|
|
|
|
|
// FIXME: Add support for optional parmameter list...
|
2007-09-11 04:33:04 +08:00
|
|
|
// If attributes exist after the method, parse them.
|
2007-10-07 10:00:24 +08:00
|
|
|
AttributeList *MethodAttrs = 0;
|
2007-10-10 01:51:17 +08:00
|
|
|
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
|
2007-10-07 10:00:24 +08:00
|
|
|
MethodAttrs = ParseAttributes();
|
|
|
|
|
|
|
|
Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
|
|
|
|
&KeyIdents[0]);
|
2007-10-27 04:53:56 +08:00
|
|
|
return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
|
2007-11-10 03:52:12 +08:00
|
|
|
mType, IDecl, DSRet, ReturnType, Sel,
|
2007-11-01 07:53:01 +08:00
|
|
|
&ArgTypeQuals[0], &KeyTypes[0],
|
2009-01-09 08:38:19 +08:00
|
|
|
&ArgNames[0], CargNames,
|
|
|
|
MethodAttrs,
|
2007-11-15 20:35:21 +08:00
|
|
|
MethodImplKind, isVariadic);
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
2008-07-26 12:03:38 +08:00
|
|
|
/// objc-protocol-refs:
|
|
|
|
/// '<' identifier-list '>'
|
|
|
|
///
|
|
|
|
bool Parser::
|
|
|
|
ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclTy*> &Protocols,
|
|
|
|
bool WarnOnDeclarations, SourceLocation &EndLoc) {
|
|
|
|
assert(Tok.is(tok::less) && "expected <");
|
|
|
|
|
|
|
|
ConsumeToken(); // the "<"
|
|
|
|
|
|
|
|
llvm::SmallVector<IdentifierLocPair, 8> ProtocolIdents;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (Tok.isNot(tok::identifier)) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
SkipUntil(tok::greater);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(),
|
|
|
|
Tok.getLocation()));
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
if (Tok.isNot(tok::comma))
|
|
|
|
break;
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Consume the '>'.
|
|
|
|
if (Tok.isNot(tok::greater)) {
|
|
|
|
Diag(Tok, diag::err_expected_greater);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
EndLoc = ConsumeAnyToken();
|
|
|
|
|
|
|
|
// Convert the list of protocols identifiers into a list of protocol decls.
|
|
|
|
Actions.FindProtocolDeclaration(WarnOnDeclarations,
|
|
|
|
&ProtocolIdents[0], ProtocolIdents.size(),
|
|
|
|
Protocols);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-class-instance-variables:
|
|
|
|
/// '{' objc-instance-variable-decl-list[opt] '}'
|
|
|
|
///
|
|
|
|
/// objc-instance-variable-decl-list:
|
|
|
|
/// objc-visibility-spec
|
|
|
|
/// objc-instance-variable-decl ';'
|
|
|
|
/// ';'
|
|
|
|
/// objc-instance-variable-decl-list objc-visibility-spec
|
|
|
|
/// objc-instance-variable-decl-list objc-instance-variable-decl ';'
|
|
|
|
/// objc-instance-variable-decl-list ';'
|
|
|
|
///
|
|
|
|
/// objc-visibility-spec:
|
|
|
|
/// @private
|
|
|
|
/// @protected
|
|
|
|
/// @public
|
2007-08-22 05:17:12 +08:00
|
|
|
/// @package [OBJC2]
|
2007-08-21 05:31:48 +08:00
|
|
|
///
|
|
|
|
/// objc-instance-variable-decl:
|
|
|
|
/// struct-declaration
|
|
|
|
///
|
2007-10-30 05:38:07 +08:00
|
|
|
void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl,
|
|
|
|
SourceLocation atLoc) {
|
2007-10-10 01:51:17 +08:00
|
|
|
assert(Tok.is(tok::l_brace) && "expected {");
|
2007-09-14 04:56:13 +08:00
|
|
|
llvm::SmallVector<DeclTy*, 32> AllIvarDecls;
|
2008-04-10 14:46:29 +08:00
|
|
|
llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators;
|
|
|
|
|
2009-01-13 02:45:55 +08:00
|
|
|
ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope);
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
llvm-svn: 61940
2009-01-09 04:45:30 +08:00
|
|
|
|
2007-08-22 05:17:12 +08:00
|
|
|
SourceLocation LBraceLoc = ConsumeBrace(); // the "{"
|
|
|
|
|
2008-04-30 07:03:51 +08:00
|
|
|
tok::ObjCKeywordKind visibility = tok::objc_protected;
|
2007-08-22 05:17:12 +08:00
|
|
|
// While we still have something to read, read the instance variables.
|
2007-10-10 01:51:17 +08:00
|
|
|
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
|
2007-08-22 05:17:12 +08:00
|
|
|
// Each iteration of this loop reads one objc-instance-variable-decl.
|
|
|
|
|
|
|
|
// Check for extraneous top-level semicolon.
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2007-08-22 05:17:12 +08:00
|
|
|
Diag(Tok, diag::ext_extra_struct_semi);
|
|
|
|
ConsumeToken();
|
|
|
|
continue;
|
|
|
|
}
|
2008-04-10 14:46:29 +08:00
|
|
|
|
2007-08-22 05:17:12 +08:00
|
|
|
// Set the default visibility to private.
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::at)) { // parse objc-visibility-spec
|
2007-08-22 05:17:12 +08:00
|
|
|
ConsumeToken(); // eat the @ sign
|
2007-08-24 02:16:40 +08:00
|
|
|
switch (Tok.getObjCKeywordID()) {
|
2007-08-22 05:17:12 +08:00
|
|
|
case tok::objc_private:
|
|
|
|
case tok::objc_public:
|
|
|
|
case tok::objc_protected:
|
|
|
|
case tok::objc_package:
|
2007-08-24 02:16:40 +08:00
|
|
|
visibility = Tok.getObjCKeywordID();
|
2007-08-22 05:17:12 +08:00
|
|
|
ConsumeToken();
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
Diag(Tok, diag::err_objc_illegal_visibility_spec);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2008-04-10 14:46:29 +08:00
|
|
|
|
|
|
|
// Parse all the comma separated declarators.
|
|
|
|
DeclSpec DS;
|
|
|
|
FieldDeclarators.clear();
|
|
|
|
ParseStructDeclaration(DS, FieldDeclarators);
|
|
|
|
|
|
|
|
// Convert them all to fields.
|
|
|
|
for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) {
|
|
|
|
FieldDeclarator &FD = FieldDeclarators[i];
|
|
|
|
// Install the declarator into interfaceDecl.
|
2008-04-11 07:32:45 +08:00
|
|
|
DeclTy *Field = Actions.ActOnIvar(CurScope,
|
2008-04-10 14:46:29 +08:00
|
|
|
DS.getSourceRange().getBegin(),
|
2008-04-11 07:32:45 +08:00
|
|
|
FD.D, FD.BitfieldSize, visibility);
|
2008-04-10 14:46:29 +08:00
|
|
|
AllIvarDecls.push_back(Field);
|
2007-09-14 04:56:13 +08:00
|
|
|
}
|
2007-09-07 05:24:23 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2007-08-22 05:17:12 +08:00
|
|
|
ConsumeToken();
|
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_expected_semi_decl_list);
|
|
|
|
// Skip to end of block or statement
|
|
|
|
SkipUntil(tok::r_brace, true, true);
|
|
|
|
}
|
|
|
|
}
|
2007-10-30 05:38:07 +08:00
|
|
|
SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
|
2007-11-01 06:11:35 +08:00
|
|
|
// Call ActOnFields() even if we don't have any decls. This is useful
|
|
|
|
// for code rewriting tools that need to be aware of the empty list.
|
|
|
|
Actions.ActOnFields(CurScope, atLoc, interfaceDecl,
|
|
|
|
&AllIvarDecls[0], AllIvarDecls.size(),
|
2008-10-03 10:03:53 +08:00
|
|
|
LBraceLoc, RBraceLoc, 0);
|
2007-08-22 05:17:12 +08:00
|
|
|
return;
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2007-08-21 05:31:48 +08:00
|
|
|
|
|
|
|
/// objc-protocol-declaration:
|
|
|
|
/// objc-protocol-definition
|
|
|
|
/// objc-protocol-forward-reference
|
|
|
|
///
|
|
|
|
/// objc-protocol-definition:
|
|
|
|
/// @protocol identifier
|
|
|
|
/// objc-protocol-refs[opt]
|
2007-09-07 05:24:23 +08:00
|
|
|
/// objc-interface-decl-list
|
2007-08-21 05:31:48 +08:00
|
|
|
/// @end
|
|
|
|
///
|
|
|
|
/// objc-protocol-forward-reference:
|
|
|
|
/// @protocol identifier-list ';'
|
|
|
|
///
|
|
|
|
/// "@protocol identifier ;" should be resolved as "@protocol
|
2007-09-07 05:24:23 +08:00
|
|
|
/// identifier-list ;": objc-interface-decl-list may not start with a
|
2007-08-21 05:31:48 +08:00
|
|
|
/// semicolon in the first alternative if objc-protocol-refs are omitted.
|
2008-09-26 12:48:09 +08:00
|
|
|
Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
|
|
|
|
AttributeList *attrList) {
|
2007-08-24 02:16:40 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
|
2007-08-23 06:17:26 +08:00
|
|
|
"ParseObjCAtProtocolDeclaration(): Expected @protocol");
|
|
|
|
ConsumeToken(); // the "protocol" identifier
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-08-23 06:17:26 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident); // missing protocol name.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// Save the protocol name, then consume it.
|
|
|
|
IdentifierInfo *protocolName = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation nameLoc = ConsumeToken();
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::semi)) { // forward declaration of one protocol.
|
2008-07-22 06:17:28 +08:00
|
|
|
IdentifierLocPair ProtoInfo(protocolName, nameLoc);
|
2007-08-23 06:17:26 +08:00
|
|
|
ConsumeToken();
|
2008-12-17 09:07:27 +08:00
|
|
|
return Actions.ActOnForwardProtocolDeclaration(AtLoc, &ProtoInfo, 1,
|
|
|
|
attrList);
|
2007-08-23 06:17:26 +08:00
|
|
|
}
|
2008-07-22 06:17:28 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::comma)) { // list of forward declarations.
|
2008-07-22 06:17:28 +08:00
|
|
|
llvm::SmallVector<IdentifierLocPair, 8> ProtocolRefs;
|
|
|
|
ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc));
|
|
|
|
|
2007-08-23 06:17:26 +08:00
|
|
|
// Parse the list of forward declarations.
|
|
|
|
while (1) {
|
|
|
|
ConsumeToken(); // the ','
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-08-23 06:17:26 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-07-22 06:17:28 +08:00
|
|
|
ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(),
|
|
|
|
Tok.getLocation()));
|
2007-08-23 06:17:26 +08:00
|
|
|
ConsumeToken(); // the identifier
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2007-08-23 06:17:26 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Consume the ';'.
|
|
|
|
if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
|
|
|
|
return 0;
|
2008-07-22 06:17:28 +08:00
|
|
|
|
2007-10-11 01:32:04 +08:00
|
|
|
return Actions.ActOnForwardProtocolDeclaration(AtLoc,
|
2007-10-03 06:39:18 +08:00
|
|
|
&ProtocolRefs[0],
|
2008-12-17 09:07:27 +08:00
|
|
|
ProtocolRefs.size(),
|
|
|
|
attrList);
|
2008-07-22 06:17:28 +08:00
|
|
|
}
|
|
|
|
|
2007-08-23 06:17:26 +08:00
|
|
|
// Last, and definitely not least, parse a protocol declaration.
|
2008-07-26 12:03:38 +08:00
|
|
|
SourceLocation EndProtoLoc;
|
2008-07-22 06:17:28 +08:00
|
|
|
|
2008-07-26 12:03:38 +08:00
|
|
|
llvm::SmallVector<DeclTy *, 8> ProtocolRefs;
|
2008-07-22 06:17:28 +08:00
|
|
|
if (Tok.is(tok::less) &&
|
2008-07-26 12:03:38 +08:00
|
|
|
ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc))
|
2008-07-22 06:17:28 +08:00
|
|
|
return 0;
|
2007-09-18 05:07:36 +08:00
|
|
|
|
2008-07-26 12:03:38 +08:00
|
|
|
DeclTy *ProtoType =
|
|
|
|
Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc,
|
|
|
|
&ProtocolRefs[0], ProtocolRefs.size(),
|
2008-09-26 12:48:09 +08:00
|
|
|
EndProtoLoc, attrList);
|
2007-09-18 05:07:36 +08:00
|
|
|
ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol);
|
2008-10-20 14:10:06 +08:00
|
|
|
return ProtoType;
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// objc-implementation:
|
|
|
|
/// objc-class-implementation-prologue
|
|
|
|
/// objc-category-implementation-prologue
|
|
|
|
///
|
|
|
|
/// objc-class-implementation-prologue:
|
|
|
|
/// @implementation identifier objc-superclass[opt]
|
|
|
|
/// objc-class-instance-variables[opt]
|
|
|
|
///
|
|
|
|
/// objc-category-implementation-prologue:
|
|
|
|
/// @implementation identifier ( identifier )
|
|
|
|
|
2007-09-01 08:26:16 +08:00
|
|
|
Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration(
|
|
|
|
SourceLocation atLoc) {
|
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
|
|
|
|
"ParseObjCAtImplementationDeclaration(): Expected @implementation");
|
|
|
|
ConsumeToken(); // the "implementation" identifier
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident); // missing class or category name.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// We have a class or category name - consume it.
|
2007-09-26 02:38:09 +08:00
|
|
|
IdentifierInfo *nameId = Tok.getIdentifierInfo();
|
2007-09-01 08:26:16 +08:00
|
|
|
SourceLocation nameLoc = ConsumeToken(); // consume class or category name
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
// we have a category implementation.
|
|
|
|
SourceLocation lparenLoc = ConsumeParen();
|
|
|
|
SourceLocation categoryLoc, rparenLoc;
|
|
|
|
IdentifierInfo *categoryId = 0;
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
categoryId = Tok.getIdentifierInfo();
|
|
|
|
categoryLoc = ConsumeToken();
|
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_expected_ident); // missing category name.
|
|
|
|
return 0;
|
|
|
|
}
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
Diag(Tok, diag::err_expected_rparen);
|
|
|
|
SkipUntil(tok::r_paren, false); // don't stop at ';'
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
rparenLoc = ConsumeParen();
|
2007-10-11 01:32:04 +08:00
|
|
|
DeclTy *ImplCatType = Actions.ActOnStartCategoryImplementation(
|
2007-10-03 00:38:50 +08:00
|
|
|
atLoc, nameId, nameLoc, categoryId,
|
|
|
|
categoryLoc);
|
2008-01-08 03:49:32 +08:00
|
|
|
ObjCImpDecl = ImplCatType;
|
2007-11-11 04:59:13 +08:00
|
|
|
return 0;
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
|
|
|
// We have a class implementation
|
2007-09-26 02:38:09 +08:00
|
|
|
SourceLocation superClassLoc;
|
|
|
|
IdentifierInfo *superClassId = 0;
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::colon)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
// We have a super class
|
|
|
|
ConsumeToken();
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident); // missing super class name.
|
|
|
|
return 0;
|
|
|
|
}
|
2007-09-26 02:38:09 +08:00
|
|
|
superClassId = Tok.getIdentifierInfo();
|
|
|
|
superClassLoc = ConsumeToken(); // Consume super class name
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
2007-10-11 01:32:04 +08:00
|
|
|
DeclTy *ImplClsType = Actions.ActOnStartClassImplementation(
|
2007-12-28 03:57:00 +08:00
|
|
|
atLoc, nameId, nameLoc,
|
2007-09-26 02:38:09 +08:00
|
|
|
superClassId, superClassLoc);
|
|
|
|
|
2007-10-30 05:38:07 +08:00
|
|
|
if (Tok.is(tok::l_brace)) // we have ivars
|
|
|
|
ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/, atLoc);
|
2008-01-08 03:49:32 +08:00
|
|
|
ObjCImpDecl = ImplClsType;
|
2007-09-01 08:26:16 +08:00
|
|
|
|
2007-11-11 04:59:13 +08:00
|
|
|
return 0;
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2007-10-30 05:38:07 +08:00
|
|
|
|
2007-09-01 08:26:16 +08:00
|
|
|
Parser::DeclTy *Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) {
|
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_end) &&
|
|
|
|
"ParseObjCAtEndDeclaration(): Expected @end");
|
2009-03-05 06:30:12 +08:00
|
|
|
DeclTy *Result = ObjCImpDecl;
|
2007-09-01 08:26:16 +08:00
|
|
|
ConsumeToken(); // the "end" identifier
|
2009-03-05 06:30:12 +08:00
|
|
|
if (ObjCImpDecl) {
|
2008-01-08 03:49:32 +08:00
|
|
|
Actions.ActOnAtEnd(atLoc, ObjCImpDecl);
|
2009-03-05 06:30:12 +08:00
|
|
|
ObjCImpDecl = 0;
|
|
|
|
}
|
2008-01-11 01:58:07 +08:00
|
|
|
else
|
|
|
|
Diag(atLoc, diag::warn_expected_implementation); // missing @implementation
|
2009-03-05 06:30:12 +08:00
|
|
|
return Result;
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2007-09-05 03:26:51 +08:00
|
|
|
|
|
|
|
/// compatibility-alias-decl:
|
|
|
|
/// @compatibility_alias alias-name class-name ';'
|
|
|
|
///
|
|
|
|
Parser::DeclTy *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
|
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
|
|
|
|
"ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
|
|
|
|
ConsumeToken(); // consume compatibility_alias
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-09-05 03:26:51 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
return 0;
|
|
|
|
}
|
2007-10-12 07:42:27 +08:00
|
|
|
IdentifierInfo *aliasId = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation aliasLoc = ConsumeToken(); // consume alias-name
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-09-05 03:26:51 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
return 0;
|
|
|
|
}
|
2007-10-12 07:42:27 +08:00
|
|
|
IdentifierInfo *classId = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation classLoc = ConsumeToken(); // consume class-name;
|
|
|
|
if (Tok.isNot(tok::semi)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_semi_after) << "@compatibility_alias";
|
2007-10-12 07:42:27 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
DeclTy *ClsType = Actions.ActOnCompatiblityAlias(atLoc,
|
|
|
|
aliasId, aliasLoc,
|
|
|
|
classId, classLoc);
|
|
|
|
return ClsType;
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
|
|
|
|
2007-09-01 08:26:16 +08:00
|
|
|
/// property-synthesis:
|
|
|
|
/// @synthesize property-ivar-list ';'
|
|
|
|
///
|
|
|
|
/// property-ivar-list:
|
|
|
|
/// property-ivar
|
|
|
|
/// property-ivar-list ',' property-ivar
|
|
|
|
///
|
|
|
|
/// property-ivar:
|
|
|
|
/// identifier
|
|
|
|
/// identifier '=' identifier
|
|
|
|
///
|
|
|
|
Parser::DeclTy *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
|
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_synthesize) &&
|
|
|
|
"ParseObjCPropertyDynamic(): Expected '@synthesize'");
|
2008-04-18 08:19:30 +08:00
|
|
|
SourceLocation loc = ConsumeToken(); // consume synthesize
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
return 0;
|
|
|
|
}
|
2007-10-10 01:51:17 +08:00
|
|
|
while (Tok.is(tok::identifier)) {
|
2008-04-18 08:19:30 +08:00
|
|
|
IdentifierInfo *propertyIvar = 0;
|
|
|
|
IdentifierInfo *propertyId = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation propertyLoc = ConsumeToken(); // consume property name
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::equal)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
// property '=' ivar-name
|
|
|
|
ConsumeToken(); // consume '='
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
break;
|
|
|
|
}
|
2008-04-18 08:19:30 +08:00
|
|
|
propertyIvar = Tok.getIdentifierInfo();
|
2007-09-01 08:26:16 +08:00
|
|
|
ConsumeToken(); // consume ivar-name
|
|
|
|
}
|
2008-04-18 08:19:30 +08:00
|
|
|
Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, true, ObjCImpDecl,
|
|
|
|
propertyId, propertyIvar);
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2007-09-01 08:26:16 +08:00
|
|
|
break;
|
|
|
|
ConsumeToken(); // consume ','
|
|
|
|
}
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::semi))
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_semi_after) << "@synthesize";
|
2007-09-01 08:26:16 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// property-dynamic:
|
|
|
|
/// @dynamic property-list
|
|
|
|
///
|
|
|
|
/// property-list:
|
|
|
|
/// identifier
|
|
|
|
/// property-list ',' identifier
|
|
|
|
///
|
|
|
|
Parser::DeclTy *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
|
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_dynamic) &&
|
|
|
|
"ParseObjCPropertyDynamic(): Expected '@dynamic'");
|
|
|
|
SourceLocation loc = ConsumeToken(); // consume dynamic
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
return 0;
|
|
|
|
}
|
2007-10-10 01:51:17 +08:00
|
|
|
while (Tok.is(tok::identifier)) {
|
2008-04-22 05:05:54 +08:00
|
|
|
IdentifierInfo *propertyId = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation propertyLoc = ConsumeToken(); // consume property name
|
|
|
|
Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, false, ObjCImpDecl,
|
|
|
|
propertyId, 0);
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2007-09-01 08:26:16 +08:00
|
|
|
break;
|
|
|
|
ConsumeToken(); // consume ','
|
|
|
|
}
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::semi))
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_semi_after) << "@dynamic";
|
2007-09-01 08:26:16 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2007-09-20 03:14:32 +08:00
|
|
|
|
|
|
|
/// objc-throw-statement:
|
|
|
|
/// throw expression[opt];
|
|
|
|
///
|
2008-12-12 04:12:42 +08:00
|
|
|
Parser::OwningStmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
|
2008-12-10 04:22:58 +08:00
|
|
|
OwningExprResult Res(Actions);
|
2007-09-20 03:14:32 +08:00
|
|
|
ConsumeToken(); // consume throw
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::semi)) {
|
2007-11-07 10:00:49 +08:00
|
|
|
Res = ParseExpression();
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2007-09-20 03:14:32 +08:00
|
|
|
SkipUntil(tok::semi);
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
|
|
|
}
|
2007-11-07 10:00:49 +08:00
|
|
|
ConsumeToken(); // consume ';'
|
2009-02-12 04:05:44 +08:00
|
|
|
return Actions.ActOnObjCAtThrowStmt(atLoc, move(Res), CurScope);
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
|
|
|
|
2008-01-30 02:21:32 +08:00
|
|
|
/// objc-synchronized-statement:
|
2008-01-31 01:38:29 +08:00
|
|
|
/// @synchronized '(' expression ')' compound-statement
|
2008-01-30 02:21:32 +08:00
|
|
|
///
|
2008-12-12 04:12:42 +08:00
|
|
|
Parser::OwningStmtResult
|
|
|
|
Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
|
2008-01-30 03:14:59 +08:00
|
|
|
ConsumeToken(); // consume synchronized
|
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_lparen_after) << "@synchronized";
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2008-01-30 03:14:59 +08:00
|
|
|
}
|
|
|
|
ConsumeParen(); // '('
|
2008-12-12 05:36:32 +08:00
|
|
|
OwningExprResult Res(ParseExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2008-01-30 03:14:59 +08:00
|
|
|
SkipUntil(tok::semi);
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2008-01-30 03:14:59 +08:00
|
|
|
}
|
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_lbrace);
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2008-01-30 03:14:59 +08:00
|
|
|
}
|
|
|
|
ConsumeParen(); // ')'
|
2008-01-31 01:38:29 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_lbrace);
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2008-01-31 01:38:29 +08:00
|
|
|
}
|
2008-06-05 04:36:13 +08:00
|
|
|
// Enter a scope to hold everything within the compound stmt. Compound
|
|
|
|
// statements can always hold declarations.
|
2008-12-10 14:34:36 +08:00
|
|
|
ParseScope BodyScope(this, Scope::DeclScope);
|
2008-06-05 04:36:13 +08:00
|
|
|
|
2008-12-12 03:30:53 +08:00
|
|
|
OwningStmtResult SynchBody(ParseCompoundStatementBody());
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2008-12-10 14:34:36 +08:00
|
|
|
BodyScope.Exit();
|
2008-12-09 21:15:23 +08:00
|
|
|
if (SynchBody.isInvalid())
|
2008-01-30 03:14:59 +08:00
|
|
|
SynchBody = Actions.ActOnNullStmt(Tok.getLocation());
|
2009-02-05 23:02:23 +08:00
|
|
|
return Actions.ActOnObjCAtSynchronizedStmt(atLoc, move(Res), move(SynchBody));
|
2008-01-30 02:21:32 +08:00
|
|
|
}
|
|
|
|
|
2007-09-20 03:14:32 +08:00
|
|
|
/// objc-try-catch-statement:
|
|
|
|
/// @try compound-statement objc-catch-list[opt]
|
|
|
|
/// @try compound-statement objc-catch-list[opt] @finally compound-statement
|
|
|
|
///
|
|
|
|
/// objc-catch-list:
|
|
|
|
/// @catch ( parameter-declaration ) compound-statement
|
|
|
|
/// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement
|
|
|
|
/// catch-parameter-declaration:
|
|
|
|
/// parameter-declaration
|
|
|
|
/// '...' [OBJC2]
|
|
|
|
///
|
2008-12-12 04:12:42 +08:00
|
|
|
Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
|
2007-09-20 03:14:32 +08:00
|
|
|
bool catch_or_finally_seen = false;
|
2008-12-12 04:12:42 +08:00
|
|
|
|
2007-09-20 03:14:32 +08:00
|
|
|
ConsumeToken(); // consume try
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_lbrace);
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
2008-12-10 04:22:58 +08:00
|
|
|
OwningStmtResult CatchStmts(Actions);
|
|
|
|
OwningStmtResult FinallyStmt(Actions);
|
2008-12-10 14:34:36 +08:00
|
|
|
ParseScope TryScope(this, Scope::DeclScope);
|
2008-12-12 03:30:53 +08:00
|
|
|
OwningStmtResult TryBody(ParseCompoundStatementBody());
|
2008-12-10 14:34:36 +08:00
|
|
|
TryScope.Exit();
|
2008-12-09 21:15:23 +08:00
|
|
|
if (TryBody.isInvalid())
|
2007-11-02 23:39:31 +08:00
|
|
|
TryBody = Actions.ActOnNullStmt(Tok.getLocation());
|
2008-11-26 06:21:31 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
while (Tok.is(tok::at)) {
|
2008-03-10 14:06:04 +08:00
|
|
|
// At this point, we need to lookahead to determine if this @ is the start
|
|
|
|
// of an @catch or @finally. We don't want to consume the @ token if this
|
|
|
|
// is an @try or @encode or something else.
|
|
|
|
Token AfterAt = GetLookAheadToken(1);
|
|
|
|
if (!AfterAt.isObjCAtKeyword(tok::objc_catch) &&
|
|
|
|
!AfterAt.isObjCAtKeyword(tok::objc_finally))
|
|
|
|
break;
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2007-11-02 08:18:53 +08:00
|
|
|
SourceLocation AtCatchFinallyLoc = ConsumeToken();
|
2007-12-28 03:57:00 +08:00
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_catch)) {
|
2009-03-04 03:52:17 +08:00
|
|
|
DeclTy *FirstPart = 0;
|
2007-11-02 07:59:59 +08:00
|
|
|
ConsumeToken(); // consume catch
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
2007-09-20 03:14:32 +08:00
|
|
|
ConsumeParen();
|
2009-02-12 04:05:44 +08:00
|
|
|
ParseScope CatchScope(this, Scope::DeclScope|Scope::AtCatchScope);
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::ellipsis)) {
|
2007-09-20 03:14:32 +08:00
|
|
|
DeclSpec DS;
|
|
|
|
ParseDeclarationSpecifiers(DS);
|
2008-12-12 04:12:42 +08:00
|
|
|
// For some odd reason, the name of the exception variable is
|
2009-03-04 03:52:17 +08:00
|
|
|
// optional. As a result, we need to use "PrototypeContext", because
|
|
|
|
// we must accept either 'declarator' or 'abstract-declarator' here.
|
|
|
|
Declarator ParmDecl(DS, Declarator::PrototypeContext);
|
|
|
|
ParseDeclarator(ParmDecl);
|
|
|
|
|
|
|
|
// Inform the actions module about the parameter declarator, so it
|
|
|
|
// gets added to the current scope.
|
|
|
|
FirstPart = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
|
2008-02-06 05:27:35 +08:00
|
|
|
} else
|
2007-09-20 03:14:32 +08:00
|
|
|
ConsumeToken(); // consume '...'
|
2007-11-02 07:59:59 +08:00
|
|
|
SourceLocation RParenLoc = ConsumeParen();
|
2008-02-15 03:27:54 +08:00
|
|
|
|
2008-12-10 04:22:58 +08:00
|
|
|
OwningStmtResult CatchBody(Actions, true);
|
2008-02-15 03:27:54 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
|
|
|
CatchBody = ParseCompoundStatementBody();
|
|
|
|
else
|
|
|
|
Diag(Tok, diag::err_expected_lbrace);
|
2008-12-09 21:15:23 +08:00
|
|
|
if (CatchBody.isInvalid())
|
2007-11-02 07:59:59 +08:00
|
|
|
CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
|
2008-12-09 21:15:23 +08:00
|
|
|
CatchStmts = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
|
2009-03-04 03:52:17 +08:00
|
|
|
RParenLoc, FirstPart, move(CatchBody),
|
2009-02-05 23:02:23 +08:00
|
|
|
move(CatchStmts));
|
2008-02-06 05:27:35 +08:00
|
|
|
} else {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
|
|
|
|
<< "@catch clause";
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
|
|
|
catch_or_finally_seen = true;
|
2008-03-10 14:06:04 +08:00
|
|
|
} else {
|
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?");
|
2008-02-06 05:27:35 +08:00
|
|
|
ConsumeToken(); // consume finally
|
2008-12-10 14:34:36 +08:00
|
|
|
ParseScope FinallyScope(this, Scope::DeclScope);
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2008-12-10 04:22:58 +08:00
|
|
|
OwningStmtResult FinallyBody(Actions, true);
|
2008-02-15 03:27:54 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
|
|
|
FinallyBody = ParseCompoundStatementBody();
|
|
|
|
else
|
|
|
|
Diag(Tok, diag::err_expected_lbrace);
|
2008-12-09 21:15:23 +08:00
|
|
|
if (FinallyBody.isInvalid())
|
2007-11-02 08:18:53 +08:00
|
|
|
FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());
|
2008-12-09 21:15:23 +08:00
|
|
|
FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc,
|
2009-02-05 23:02:23 +08:00
|
|
|
move(FinallyBody));
|
2007-09-20 03:14:32 +08:00
|
|
|
catch_or_finally_seen = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-11-02 23:39:31 +08:00
|
|
|
if (!catch_or_finally_seen) {
|
2007-09-20 03:14:32 +08:00
|
|
|
Diag(atLoc, diag::err_missing_catch_finally);
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2007-11-02 23:39:31 +08:00
|
|
|
}
|
2009-02-05 23:02:23 +08:00
|
|
|
return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody), move(CatchStmts),
|
|
|
|
move(FinallyStmt));
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
2007-09-01 08:26:16 +08:00
|
|
|
|
2007-09-07 05:24:23 +08:00
|
|
|
/// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
|
2007-09-01 08:26:16 +08:00
|
|
|
///
|
2007-11-14 07:01:27 +08:00
|
|
|
Parser::DeclTy *Parser::ParseObjCMethodDefinition() {
|
2008-01-08 03:49:32 +08:00
|
|
|
DeclTy *MDecl = ParseObjCMethodPrototype(ObjCImpDecl);
|
2009-03-05 10:03:49 +08:00
|
|
|
|
2009-03-05 16:00:35 +08:00
|
|
|
PrettyStackTraceActionsDecl CrashInfo(MDecl, Tok.getLocation(), Actions,
|
|
|
|
PP.getSourceManager(),
|
|
|
|
"parsing Objective-C method");
|
2009-03-05 10:03:49 +08:00
|
|
|
|
2007-09-01 08:26:16 +08:00
|
|
|
// parse optional ';'
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::semi))
|
2007-09-01 08:26:16 +08:00
|
|
|
ConsumeToken();
|
|
|
|
|
2007-11-12 03:54:21 +08:00
|
|
|
// We should have an opening brace now.
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2008-03-01 05:48:07 +08:00
|
|
|
Diag(Tok, diag::err_expected_method_body);
|
2007-11-12 03:54:21 +08:00
|
|
|
|
|
|
|
// Skip over garbage, until we get to '{'. Don't eat the '{'.
|
|
|
|
SkipUntil(tok::l_brace, true, true);
|
|
|
|
|
|
|
|
// If we didn't find the '{', bail out.
|
|
|
|
if (Tok.isNot(tok::l_brace))
|
2007-11-14 07:01:27 +08:00
|
|
|
return 0;
|
2007-09-01 08:26:16 +08:00
|
|
|
}
|
2007-11-12 03:54:21 +08:00
|
|
|
SourceLocation BraceLoc = Tok.getLocation();
|
|
|
|
|
|
|
|
// Enter a scope for the method body.
|
2008-12-10 14:34:36 +08:00
|
|
|
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
|
2007-11-12 03:54:21 +08:00
|
|
|
|
|
|
|
// Tell the actions module that we have entered a method definition with the
|
2008-07-26 01:57:26 +08:00
|
|
|
// specified Declarator for the method.
|
2009-03-01 00:59:13 +08:00
|
|
|
Actions.ActOnStartOfObjCMethodDef(CurScope, MDecl);
|
2008-12-12 03:30:53 +08:00
|
|
|
|
|
|
|
OwningStmtResult FnBody(ParseCompoundStatementBody());
|
|
|
|
|
2007-11-12 03:54:21 +08:00
|
|
|
// If the function body could not be parsed, make a bogus compoundstmt.
|
2008-12-09 21:15:23 +08:00
|
|
|
if (FnBody.isInvalid())
|
2008-12-21 20:04:03 +08:00
|
|
|
FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc,
|
|
|
|
MultiStmtArg(Actions), false);
|
2008-12-14 00:23:55 +08:00
|
|
|
|
2009-03-03 06:00:56 +08:00
|
|
|
// TODO: Pass argument information.
|
|
|
|
Actions.ActOnFinishFunctionBody(MDecl, move(FnBody));
|
|
|
|
|
2007-11-12 03:54:21 +08:00
|
|
|
// Leave the function body scope.
|
2008-12-10 14:34:36 +08:00
|
|
|
BodyScope.Exit();
|
2008-12-14 00:23:55 +08:00
|
|
|
|
2007-11-14 07:01:27 +08:00
|
|
|
return MDecl;
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2007-08-22 01:43:55 +08:00
|
|
|
|
2008-12-12 04:12:42 +08:00
|
|
|
Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
|
2008-02-06 05:27:35 +08:00
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_try)) {
|
2008-03-10 14:06:04 +08:00
|
|
|
return ParseObjCTryStmt(AtLoc);
|
2008-02-06 05:27:35 +08:00
|
|
|
} else if (Tok.isObjCAtKeyword(tok::objc_throw))
|
|
|
|
return ParseObjCThrowStmt(AtLoc);
|
|
|
|
else if (Tok.isObjCAtKeyword(tok::objc_synchronized))
|
|
|
|
return ParseObjCSynchronizedStmt(AtLoc);
|
2008-12-12 06:33:27 +08:00
|
|
|
OwningExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2008-02-06 05:27:35 +08:00
|
|
|
// If the expression is invalid, skip ahead to the next semicolon. Not
|
|
|
|
// doing this opens us up to the possibility of infinite loops if
|
|
|
|
// ParseExpression does not consume any tokens.
|
|
|
|
SkipUntil(tok::semi);
|
2008-12-12 04:12:42 +08:00
|
|
|
return StmtError();
|
2008-02-06 05:27:35 +08:00
|
|
|
}
|
|
|
|
// Otherwise, eat the semicolon.
|
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
|
2009-02-05 23:02:23 +08:00
|
|
|
return Actions.ActOnExprStmt(move(Res));
|
2008-02-06 05:27:35 +08:00
|
|
|
}
|
|
|
|
|
2008-12-13 23:32:12 +08:00
|
|
|
Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
|
2007-08-22 01:43:55 +08:00
|
|
|
switch (Tok.getKind()) {
|
2007-12-12 09:04:12 +08:00
|
|
|
case tok::string_literal: // primary-expression: string-literal
|
|
|
|
case tok::wide_string_literal:
|
2008-12-13 23:32:12 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
|
2007-12-12 09:04:12 +08:00
|
|
|
default:
|
2008-08-05 14:19:09 +08:00
|
|
|
if (Tok.getIdentifierInfo() == 0)
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(AtLoc, diag::err_unexpected_at));
|
2008-12-12 05:36:32 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
|
|
|
|
case tok::objc_encode:
|
2008-12-13 23:32:12 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc));
|
2008-08-05 14:19:09 +08:00
|
|
|
case tok::objc_protocol:
|
2008-12-13 23:32:12 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc));
|
2008-08-05 14:19:09 +08:00
|
|
|
case tok::objc_selector:
|
2008-12-13 23:32:12 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc));
|
2008-08-05 14:19:09 +08:00
|
|
|
default:
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(AtLoc, diag::err_unexpected_at));
|
2008-08-05 14:19:09 +08:00
|
|
|
}
|
2007-08-22 01:43:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-06 03:52:07 +08:00
|
|
|
/// objc-message-expr:
|
|
|
|
/// '[' objc-receiver objc-message-args ']'
|
|
|
|
///
|
|
|
|
/// objc-receiver:
|
|
|
|
/// expression
|
|
|
|
/// class-name
|
|
|
|
/// type-name
|
2008-12-13 23:32:12 +08:00
|
|
|
Parser::OwningExprResult Parser::ParseObjCMessageExpression() {
|
2008-01-26 02:59:06 +08:00
|
|
|
assert(Tok.is(tok::l_square) && "'[' expected");
|
|
|
|
SourceLocation LBracLoc = ConsumeBracket(); // consume '['
|
|
|
|
|
|
|
|
// Parse receiver
|
2008-01-26 03:25:00 +08:00
|
|
|
if (isTokObjCMessageIdentifierReceiver()) {
|
2008-01-26 02:59:06 +08:00
|
|
|
IdentifierInfo *ReceiverName = Tok.getIdentifierInfo();
|
2008-11-19 23:54:23 +08:00
|
|
|
SourceLocation NameLoc = ConsumeToken();
|
2008-12-13 23:32:12 +08:00
|
|
|
return ParseObjCMessageExpressionBody(LBracLoc, NameLoc, ReceiverName,
|
|
|
|
ExprArg(Actions));
|
2008-01-26 02:59:06 +08:00
|
|
|
}
|
|
|
|
|
2008-12-12 05:36:32 +08:00
|
|
|
OwningExprResult Res(ParseExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2008-01-26 03:43:26 +08:00
|
|
|
SkipUntil(tok::r_square);
|
2008-12-13 23:32:12 +08:00
|
|
|
return move(Res);
|
2008-01-26 02:59:06 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-12-09 21:15:23 +08:00
|
|
|
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
|
2009-02-05 23:02:23 +08:00
|
|
|
0, move(Res));
|
2008-01-26 02:59:06 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-01-26 02:59:06 +08:00
|
|
|
/// ParseObjCMessageExpressionBody - Having parsed "'[' objc-receiver", parse
|
|
|
|
/// the rest of a message expression.
|
2008-12-13 23:32:12 +08:00
|
|
|
///
|
2007-09-06 03:52:07 +08:00
|
|
|
/// objc-message-args:
|
|
|
|
/// objc-selector
|
|
|
|
/// objc-keywordarg-list
|
|
|
|
///
|
|
|
|
/// objc-keywordarg-list:
|
|
|
|
/// objc-keywordarg
|
|
|
|
/// objc-keywordarg-list objc-keywordarg
|
|
|
|
///
|
|
|
|
/// objc-keywordarg:
|
|
|
|
/// selector-name[opt] ':' objc-keywordexpr
|
|
|
|
///
|
|
|
|
/// objc-keywordexpr:
|
|
|
|
/// nonempty-expr-list
|
|
|
|
///
|
|
|
|
/// nonempty-expr-list:
|
|
|
|
/// assignment-expression
|
|
|
|
/// nonempty-expr-list , assignment-expression
|
2008-12-13 23:32:12 +08:00
|
|
|
///
|
|
|
|
Parser::OwningExprResult
|
2008-01-26 02:59:06 +08:00
|
|
|
Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
|
2008-11-19 23:54:23 +08:00
|
|
|
SourceLocation NameLoc,
|
2008-01-26 02:59:06 +08:00
|
|
|
IdentifierInfo *ReceiverName,
|
2008-12-13 23:32:12 +08:00
|
|
|
ExprArg ReceiverExpr) {
|
2007-09-06 07:08:20 +08:00
|
|
|
// Parse objc-selector
|
2007-10-11 08:55:41 +08:00
|
|
|
SourceLocation Loc;
|
|
|
|
IdentifierInfo *selIdent = ParseObjCSelector(Loc);
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
|
2009-02-15 02:21:46 +08:00
|
|
|
SourceLocation SelectorLoc = Loc;
|
|
|
|
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
|
2008-11-26 06:21:31 +08:00
|
|
|
ExprVector KeyExprs(Actions);
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::colon)) {
|
2007-09-06 07:08:20 +08:00
|
|
|
while (1) {
|
|
|
|
// Each iteration parses a single keyword argument.
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
KeyIdents.push_back(selIdent);
|
2007-09-18 04:25:27 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::colon)) {
|
2007-09-06 07:08:20 +08:00
|
|
|
Diag(Tok, diag::err_expected_colon);
|
2008-08-05 14:19:09 +08:00
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
|
|
|
SkipUntil(tok::r_square);
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError();
|
2007-09-06 07:08:20 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
llvm-svn: 42395
2007-09-27 22:38:14 +08:00
|
|
|
ConsumeToken(); // Eat the ':'.
|
2007-09-06 07:08:20 +08:00
|
|
|
/// Parse the expression after ':'
|
2008-12-12 05:36:32 +08:00
|
|
|
OwningExprResult Res(ParseAssignmentExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2008-08-05 14:19:09 +08:00
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
|
|
|
SkipUntil(tok::r_square);
|
2008-12-13 23:32:12 +08:00
|
|
|
return move(Res);
|
2007-09-18 04:25:27 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-09-18 04:25:27 +08:00
|
|
|
// We have a valid expression.
|
2008-12-10 08:02:53 +08:00
|
|
|
KeyExprs.push_back(Res.release());
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-09-18 04:25:27 +08:00
|
|
|
// Check for another keyword selector.
|
2007-10-11 08:55:41 +08:00
|
|
|
selIdent = ParseObjCSelector(Loc);
|
2007-10-10 01:51:17 +08:00
|
|
|
if (!selIdent && Tok.isNot(tok::colon))
|
2007-09-06 07:08:20 +08:00
|
|
|
break;
|
|
|
|
// We have a selector or a colon, continue parsing.
|
|
|
|
}
|
|
|
|
// Parse the, optional, argument list, comma separated.
|
2007-10-10 01:51:17 +08:00
|
|
|
while (Tok.is(tok::comma)) {
|
2007-11-15 21:05:42 +08:00
|
|
|
ConsumeToken(); // Eat the ','.
|
|
|
|
/// Parse the expression after ','
|
2008-12-12 05:36:32 +08:00
|
|
|
OwningExprResult Res(ParseAssignmentExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2008-08-05 14:19:09 +08:00
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
|
|
|
SkipUntil(tok::r_square);
|
2008-12-13 23:32:12 +08:00
|
|
|
return move(Res);
|
2007-11-15 21:05:42 +08:00
|
|
|
}
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2007-11-15 21:05:42 +08:00
|
|
|
// We have a valid expression.
|
2008-12-10 08:02:53 +08:00
|
|
|
KeyExprs.push_back(Res.release());
|
2007-09-06 07:08:20 +08:00
|
|
|
}
|
|
|
|
} else if (!selIdent) {
|
|
|
|
Diag(Tok, diag::err_expected_ident); // missing selector name.
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
|
|
|
SkipUntil(tok::r_square);
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError();
|
2007-09-06 07:08:20 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::r_square)) {
|
2007-09-06 07:08:20 +08:00
|
|
|
Diag(Tok, diag::err_expected_rsquare);
|
2008-08-05 14:19:09 +08:00
|
|
|
// We must manually skip to a ']', otherwise the expression skipper will
|
|
|
|
// stop at the ']' when it skips to the ';'. We want it to skip beyond
|
|
|
|
// the enclosing expression.
|
|
|
|
SkipUntil(tok::r_square);
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError();
|
2007-09-06 07:08:20 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-01-26 02:59:06 +08:00
|
|
|
SourceLocation RBracLoc = ConsumeBracket(); // consume ']'
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-10-06 02:42:47 +08:00
|
|
|
unsigned nKeys = KeyIdents.size();
|
2007-10-07 10:00:24 +08:00
|
|
|
if (nKeys == 0)
|
|
|
|
KeyIdents.push_back(selIdent);
|
|
|
|
Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]);
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-10-07 10:00:24 +08:00
|
|
|
// We've just parsed a keyword message.
|
2008-12-13 23:32:12 +08:00
|
|
|
if (ReceiverName)
|
|
|
|
return Owned(Actions.ActOnClassMessage(CurScope, ReceiverName, Sel,
|
2009-02-15 02:21:46 +08:00
|
|
|
LBracLoc, NameLoc, SelectorLoc,
|
|
|
|
RBracLoc,
|
2008-12-13 23:32:12 +08:00
|
|
|
KeyExprs.take(), KeyExprs.size()));
|
|
|
|
return Owned(Actions.ActOnInstanceMessage(ReceiverExpr.release(), Sel,
|
2009-02-15 02:21:46 +08:00
|
|
|
LBracLoc, SelectorLoc, RBracLoc,
|
2008-12-13 23:32:12 +08:00
|
|
|
KeyExprs.take(), KeyExprs.size()));
|
2007-09-06 03:52:07 +08:00
|
|
|
}
|
|
|
|
|
2008-12-13 23:32:12 +08:00
|
|
|
Parser::OwningExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
|
2008-12-12 06:51:44 +08:00
|
|
|
OwningExprResult Res(ParseStringLiteralExpression());
|
2008-12-13 23:32:12 +08:00
|
|
|
if (Res.isInvalid()) return move(Res);
|
|
|
|
|
2007-12-12 09:04:12 +08:00
|
|
|
// @"foo" @"bar" is a valid concatenated string. Eat any subsequent string
|
|
|
|
// expressions. At this point, we know that the only valid thing that starts
|
|
|
|
// with '@' is an @"".
|
|
|
|
llvm::SmallVector<SourceLocation, 4> AtLocs;
|
2008-11-26 06:21:31 +08:00
|
|
|
ExprVector AtStrings(Actions);
|
2007-12-12 09:04:12 +08:00
|
|
|
AtLocs.push_back(AtLoc);
|
2008-12-10 08:02:53 +08:00
|
|
|
AtStrings.push_back(Res.release());
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2007-12-12 09:04:12 +08:00
|
|
|
while (Tok.is(tok::at)) {
|
|
|
|
AtLocs.push_back(ConsumeToken()); // eat the @.
|
|
|
|
|
2008-12-10 04:22:58 +08:00
|
|
|
// Invalid unless there is a string literal.
|
2009-02-18 13:56:09 +08:00
|
|
|
if (!isTokenStringLiteral())
|
|
|
|
return ExprError(Diag(Tok, diag::err_objc_concat_string));
|
2007-12-12 09:04:12 +08:00
|
|
|
|
2009-02-18 13:56:09 +08:00
|
|
|
OwningExprResult Lit(ParseStringLiteralExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Lit.isInvalid())
|
2008-12-13 23:32:12 +08:00
|
|
|
return move(Lit);
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2008-12-10 08:02:53 +08:00
|
|
|
AtStrings.push_back(Lit.release());
|
2007-12-12 09:04:12 +08:00
|
|
|
}
|
2008-12-13 23:32:12 +08:00
|
|
|
|
|
|
|
return Owned(Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.take(),
|
|
|
|
AtStrings.size()));
|
2007-08-22 01:43:55 +08:00
|
|
|
}
|
2007-08-22 23:14:15 +08:00
|
|
|
|
|
|
|
/// objc-encode-expression:
|
|
|
|
/// @encode ( type-name )
|
2008-12-13 23:32:12 +08:00
|
|
|
Parser::OwningExprResult
|
|
|
|
Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
|
2007-08-24 02:16:40 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-08-22 23:14:15 +08:00
|
|
|
SourceLocation EncLoc = ConsumeToken();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
if (Tok.isNot(tok::l_paren))
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@encode");
|
|
|
|
|
2007-08-22 23:14:15 +08:00
|
|
|
SourceLocation LParenLoc = ConsumeParen();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2009-02-19 01:45:20 +08:00
|
|
|
TypeResult Ty = ParseTypeName();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-08-23 23:31:37 +08:00
|
|
|
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2009-02-19 01:45:20 +08:00
|
|
|
if (Ty.isInvalid())
|
|
|
|
return ExprError();
|
|
|
|
|
|
|
|
return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, LParenLoc,
|
|
|
|
Ty.get(), RParenLoc));
|
2007-08-22 23:14:15 +08:00
|
|
|
}
|
2007-08-23 23:25:28 +08:00
|
|
|
|
|
|
|
/// objc-protocol-expression
|
|
|
|
/// @protocol ( protocol-name )
|
2008-12-13 23:32:12 +08:00
|
|
|
Parser::OwningExprResult
|
|
|
|
Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
|
2007-08-23 23:25:28 +08:00
|
|
|
SourceLocation ProtoLoc = ConsumeToken();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
if (Tok.isNot(tok::l_paren))
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@protocol");
|
|
|
|
|
2007-08-23 23:25:28 +08:00
|
|
|
SourceLocation LParenLoc = ConsumeParen();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
if (Tok.isNot(tok::identifier))
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_ident));
|
|
|
|
|
2007-10-18 00:58:11 +08:00
|
|
|
IdentifierInfo *protocolId = Tok.getIdentifierInfo();
|
2007-08-23 23:25:28 +08:00
|
|
|
ConsumeToken();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2007-08-23 23:31:37 +08:00
|
|
|
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2007-08-23 23:25:28 +08:00
|
|
|
|
2008-12-13 23:32:12 +08:00
|
|
|
return Owned(Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
|
|
|
|
LParenLoc, RParenLoc));
|
2007-08-23 23:25:28 +08:00
|
|
|
}
|
2007-10-16 07:39:13 +08:00
|
|
|
|
|
|
|
/// objc-selector-expression
|
|
|
|
/// @selector '(' objc-keyword-selector ')'
|
2008-12-13 23:32:12 +08:00
|
|
|
Parser::OwningExprResult
|
|
|
|
Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
|
2007-10-16 07:39:13 +08:00
|
|
|
SourceLocation SelectorLoc = ConsumeToken();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-08-05 14:19:09 +08:00
|
|
|
if (Tok.isNot(tok::l_paren))
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector");
|
|
|
|
|
2007-10-17 04:40:23 +08:00
|
|
|
llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
|
2007-10-16 07:39:13 +08:00
|
|
|
SourceLocation LParenLoc = ConsumeParen();
|
|
|
|
SourceLocation sLoc;
|
|
|
|
IdentifierInfo *SelIdent = ParseObjCSelector(sLoc);
|
2008-12-13 23:32:12 +08:00
|
|
|
if (!SelIdent && Tok.isNot(tok::colon)) // missing selector name.
|
|
|
|
return ExprError(Diag(Tok, diag::err_expected_ident));
|
|
|
|
|
2007-10-17 04:40:23 +08:00
|
|
|
KeyIdents.push_back(SelIdent);
|
2007-12-06 06:21:29 +08:00
|
|
|
unsigned nColons = 0;
|
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2007-10-16 07:39:13 +08:00
|
|
|
while (1) {
|
2008-08-05 14:19:09 +08:00
|
|
|
if (Tok.isNot(tok::colon))
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_colon));
|
|
|
|
|
2007-12-28 03:57:00 +08:00
|
|
|
nColons++;
|
2007-10-16 07:39:13 +08:00
|
|
|
ConsumeToken(); // Eat the ':'.
|
|
|
|
if (Tok.is(tok::r_paren))
|
|
|
|
break;
|
|
|
|
// Check for another keyword selector.
|
|
|
|
SourceLocation Loc;
|
|
|
|
SelIdent = ParseObjCSelector(Loc);
|
2007-10-17 04:40:23 +08:00
|
|
|
KeyIdents.push_back(SelIdent);
|
2007-10-16 07:39:13 +08:00
|
|
|
if (!SelIdent && Tok.isNot(tok::colon))
|
|
|
|
break;
|
|
|
|
}
|
2007-12-06 06:21:29 +08:00
|
|
|
}
|
2007-10-16 07:39:13 +08:00
|
|
|
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2007-12-06 06:21:29 +08:00
|
|
|
Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
|
2008-12-13 23:32:12 +08:00
|
|
|
return Owned(Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
|
|
|
|
LParenLoc, RParenLoc));
|
2007-10-19 23:38:32 +08:00
|
|
|
}
|