2006-11-05 10:08:13 +08:00
|
|
|
//===--- ParseObjc.cpp - Objective C Parsing ------------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file was developed by Steve Naroff and is distributed under
|
|
|
|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// 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"
|
2006-11-05 10:08:13 +08:00
|
|
|
#include "clang/Basic/Diagnostic.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
|
|
|
|
/// ParseExternalDeclaration:
|
|
|
|
/// 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()) {
|
2006-11-05 10:08:13 +08:00
|
|
|
case tok::objc_class:
|
2006-11-08 14:10:32 +08:00
|
|
|
return ParseObjCAtClassDeclaration(AtLoc);
|
2006-11-05 10:08:13 +08:00
|
|
|
case tok::objc_interface:
|
2007-08-21 05:31:48 +08:00
|
|
|
return ParseObjCAtInterfaceDeclaration(AtLoc);
|
2006-11-05 10:08:13 +08:00
|
|
|
case tok::objc_protocol:
|
2007-08-23 06:17:26 +08:00
|
|
|
return ParseObjCAtProtocolDeclaration(AtLoc);
|
2006-11-05 10:08:13 +08:00
|
|
|
case tok::objc_implementation:
|
2007-09-07 05:24:23 +08:00
|
|
|
return ObjcImpDecl = ParseObjCAtImplementationDeclaration(AtLoc);
|
2006-11-05 10:08:13 +08:00
|
|
|
case tok::objc_end:
|
2007-09-01 08:26:16 +08:00
|
|
|
return ParseObjCAtEndDeclaration(AtLoc);
|
2006-11-05 10:08:13 +08:00
|
|
|
case tok::objc_compatibility_alias:
|
2007-09-05 03:26:51 +08:00
|
|
|
return ParseObjCAtAliasDeclaration(AtLoc);
|
2007-09-01 08:26:16 +08:00
|
|
|
case tok::objc_synthesize:
|
|
|
|
return ParseObjCPropertySynthesize(AtLoc);
|
|
|
|
case tok::objc_dynamic:
|
|
|
|
return ParseObjCPropertyDynamic(AtLoc);
|
2006-11-05 10:08:13 +08:00
|
|
|
default:
|
|
|
|
Diag(AtLoc, diag::err_unexpected_at);
|
|
|
|
SkipUntil(tok::semi);
|
2007-08-21 05:31:48 +08:00
|
|
|
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-09-19 04:26:58 +08:00
|
|
|
llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
|
2007-08-21 05:31:48 +08:00
|
|
|
|
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();
|
2007-10-30 10:23:23 +08:00
|
|
|
SourceLocation endProtoLoc;
|
2007-08-21 05:31:48 +08:00
|
|
|
// Next, we need to check for any protocol references.
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::less)) {
|
2007-10-30 10:23:23 +08:00
|
|
|
if (ParseObjCProtocolReferences(ProtocolRefs, endProtoLoc))
|
2007-08-21 05:31:48 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
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(),
|
|
|
|
endProtoLoc);
|
2007-09-19 04:26:58 +08:00
|
|
|
|
|
|
|
ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword);
|
2007-08-21 05:31:48 +08:00
|
|
|
|
2007-08-23 00:35:03 +08:00
|
|
|
// The @ sign was already consumed by ParseObjCInterfaceDeclList().
|
2007-08-24 02:16:40 +08:00
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_end)) {
|
2007-08-23 00:35:03 +08:00
|
|
|
ConsumeToken(); // the "end" identifier
|
2007-10-09 02:53:38 +08:00
|
|
|
return CategoryType;
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
2007-08-23 00:35:03 +08:00
|
|
|
Diag(Tok, diag::err_objc_missing_end);
|
2007-08-21 05:31:48 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// 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.
|
2007-09-06 07:30:30 +08:00
|
|
|
llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
|
2007-10-30 10:23:23 +08:00
|
|
|
SourceLocation endProtoLoc;
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::less)) {
|
2007-10-30 10:23:23 +08:00
|
|
|
if (ParseObjCProtocolReferences(ProtocolRefs, endProtoLoc))
|
2007-08-21 05:31:48 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2007-10-11 01:32:04 +08:00
|
|
|
DeclTy *ClsType = Actions.ActOnStartClassInterface(
|
2007-09-26 02:38:09 +08:00
|
|
|
atLoc, nameId, nameLoc,
|
2007-09-06 07:30:30 +08:00
|
|
|
superClassId, superClassLoc, &ProtocolRefs[0],
|
2007-10-30 10:23:23 +08:00
|
|
|
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);
|
2007-08-23 00:35:03 +08:00
|
|
|
|
|
|
|
// The @ sign was already consumed by ParseObjCInterfaceDeclList().
|
2007-08-24 02:16:40 +08:00
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_end)) {
|
2007-08-23 00:35:03 +08:00
|
|
|
ConsumeToken(); // the "end" identifier
|
2007-09-11 04:51:04 +08:00
|
|
|
return ClsType;
|
2007-08-21 05:31:48 +08:00
|
|
|
}
|
2007-08-23 00:35:03 +08:00
|
|
|
Diag(Tok, diag::err_objc_missing_end);
|
2007-08-21 05:31:48 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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,
|
|
|
|
tok::ObjCKeywordKind contextKey) {
|
2007-09-11 04:33:04 +08:00
|
|
|
llvm::SmallVector<DeclTy*, 32> allMethods;
|
2007-09-18 08:25:23 +08:00
|
|
|
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
|
2007-10-30 05:38:07 +08:00
|
|
|
SourceLocation AtEndLoc;
|
|
|
|
|
2007-08-23 00:35:03 +08:00
|
|
|
while (1) {
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::at)) {
|
2007-08-23 00:35:03 +08:00
|
|
|
SourceLocation AtLoc = ConsumeToken(); // the "@"
|
2007-08-24 02:16:40 +08:00
|
|
|
tok::ObjCKeywordKind ocKind = Tok.getObjCKeywordID();
|
2007-08-23 00:35:03 +08:00
|
|
|
|
|
|
|
if (ocKind == tok::objc_end) { // terminate list
|
2007-10-30 05:38:07 +08:00
|
|
|
AtEndLoc = AtLoc;
|
2007-09-11 04:33:04 +08:00
|
|
|
break;
|
2007-08-23 00:35:03 +08:00
|
|
|
} else if (ocKind == tok::objc_required) { // protocols only
|
|
|
|
ConsumeToken();
|
2007-09-18 08:25:23 +08:00
|
|
|
MethodImplKind = ocKind;
|
2007-09-18 05:07:36 +08:00
|
|
|
if (contextKey != tok::objc_protocol)
|
|
|
|
Diag(AtLoc, diag::err_objc_protocol_required);
|
2007-08-23 00:35:03 +08:00
|
|
|
} else if (ocKind == tok::objc_optional) { // protocols only
|
|
|
|
ConsumeToken();
|
2007-09-18 08:25:23 +08:00
|
|
|
MethodImplKind = ocKind;
|
2007-09-18 05:07:36 +08:00
|
|
|
if (contextKey != tok::objc_protocol)
|
|
|
|
Diag(AtLoc, diag::err_objc_protocol_optional);
|
2007-08-23 00:35:03 +08:00
|
|
|
} else if (ocKind == tok::objc_property) {
|
2007-09-13 02:23:47 +08:00
|
|
|
ParseObjCPropertyDecl(interfaceDecl);
|
2007-08-23 00:35:03 +08:00
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_objc_illegal_interface_qual);
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
|
|
|
}
|
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.
|
2007-09-17 23:07:43 +08:00
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,"method proto");
|
2007-08-23 00:35:03 +08:00
|
|
|
continue;
|
|
|
|
}
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::semi))
|
2007-08-23 00:35:03 +08:00
|
|
|
ConsumeToken();
|
2007-10-10 01:51:17 +08:00
|
|
|
else if (Tok.is(tok::eof))
|
2007-09-11 04:33:04 +08:00
|
|
|
break;
|
2007-09-06 07:30:30 +08:00
|
|
|
else {
|
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();
|
2007-09-06 07:30:30 +08:00
|
|
|
}
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
2007-10-30 11:43:13 +08:00
|
|
|
/// Insert collected methods declarations into the @interface object.
|
|
|
|
/// This action is executed even if we don't have any methods (so the @end
|
|
|
|
/// can be recorded properly).
|
|
|
|
Actions.ActOnAddMethodsToObjcDecl(CurScope, interfaceDecl, &allMethods[0],
|
|
|
|
allMethods.size(), AtEndLoc);
|
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
|
|
|
|
///
|
|
|
|
void Parser::ParseObjCPropertyAttribute (DeclTy *interfaceDecl) {
|
|
|
|
SourceLocation loc = ConsumeParen(); // consume '('
|
|
|
|
while (isObjCPropertyAttribute()) {
|
|
|
|
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
|
|
|
// getter/setter require extra treatment.
|
|
|
|
if (II == ObjcPropertyAttrs[objc_getter] ||
|
|
|
|
II == ObjcPropertyAttrs[objc_setter]) {
|
|
|
|
// skip getter/setter part.
|
|
|
|
SourceLocation loc = ConsumeToken();
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::equal)) {
|
2007-09-01 00:11:31 +08:00
|
|
|
loc = ConsumeToken();
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
2007-09-01 00:11:31 +08:00
|
|
|
if (II == ObjcPropertyAttrs[objc_setter]) {
|
|
|
|
loc = ConsumeToken(); // consume method name
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::colon)) {
|
2007-09-01 00:11:31 +08:00
|
|
|
Diag(loc, diag::err_expected_colon);
|
|
|
|
SkipUntil(tok::r_paren,true,true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Diag(loc, diag::err_expected_ident);
|
|
|
|
SkipUntil(tok::r_paren,true,true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Diag(loc, diag::err_objc_expected_equal);
|
|
|
|
SkipUntil(tok::r_paren,true,true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ConsumeToken(); // consume last attribute token
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::comma)) {
|
2007-09-01 00:11:31 +08:00
|
|
|
loc = ConsumeToken();
|
|
|
|
continue;
|
|
|
|
}
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::r_paren))
|
2007-09-01 00:11:31 +08:00
|
|
|
break;
|
|
|
|
Diag(loc, diag::err_expected_rparen);
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return;
|
|
|
|
}
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::r_paren))
|
2007-09-01 00:11:31 +08:00
|
|
|
ConsumeParen();
|
|
|
|
else {
|
|
|
|
Diag(loc, diag::err_objc_expected_property_attr);
|
|
|
|
SkipUntil(tok::r_paren); // recover from error inside attribute list
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Main routine to parse property declaration.
|
|
|
|
///
|
|
|
|
/// @property property-attr-decl[opt] property-component-decl ';'
|
|
|
|
///
|
|
|
|
void Parser::ParseObjCPropertyDecl(DeclTy *interfaceDecl) {
|
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_property) &&
|
|
|
|
"ParseObjCPropertyDecl(): Expected @property");
|
|
|
|
ConsumeToken(); // the "property" identifier
|
|
|
|
// Parse property attribute list, if any.
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
2007-09-01 00:11:31 +08:00
|
|
|
// property has attribute list.
|
|
|
|
ParseObjCPropertyAttribute(0/*FIXME*/);
|
|
|
|
}
|
|
|
|
// Parse declaration portion of @property.
|
|
|
|
llvm::SmallVector<DeclTy*, 32> PropertyDecls;
|
|
|
|
ParseStructDeclaration(interfaceDecl, PropertyDecls);
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::semi))
|
2007-09-01 00:11:31 +08:00
|
|
|
ConsumeToken();
|
|
|
|
else {
|
|
|
|
Diag(Tok, diag::err_expected_semi_decl_list);
|
|
|
|
SkipUntil(tok::r_brace, true, true);
|
|
|
|
}
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2007-08-21 05:31:48 +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,
|
|
|
|
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-10-27 04:53:56 +08:00
|
|
|
DeclTy *MDecl = ParseObjCMethodDecl(mLoc, methodType, 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:
|
|
|
|
case tok::kw_typeof:
|
|
|
|
case tok::kw___alignof:
|
|
|
|
case tok::kw_auto:
|
|
|
|
case tok::kw_break:
|
|
|
|
case tok::kw_case:
|
|
|
|
case tok::kw_char:
|
|
|
|
case tok::kw_const:
|
|
|
|
case tok::kw_continue:
|
|
|
|
case tok::kw_default:
|
|
|
|
case tok::kw_do:
|
|
|
|
case tok::kw_double:
|
|
|
|
case tok::kw_else:
|
|
|
|
case tok::kw_enum:
|
|
|
|
case tok::kw_extern:
|
|
|
|
case tok::kw_float:
|
|
|
|
case tok::kw_for:
|
|
|
|
case tok::kw_goto:
|
|
|
|
case tok::kw_if:
|
|
|
|
case tok::kw_inline:
|
|
|
|
case tok::kw_int:
|
|
|
|
case tok::kw_long:
|
|
|
|
case tok::kw_register:
|
|
|
|
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_struct:
|
|
|
|
case tok::kw_switch:
|
|
|
|
case tok::kw_typedef:
|
|
|
|
case tok::kw_union:
|
|
|
|
case tok::kw_unsigned:
|
|
|
|
case tok::kw_void:
|
|
|
|
case tok::kw_volatile:
|
|
|
|
case tok::kw_while:
|
|
|
|
case tok::kw__Bool:
|
|
|
|
case tok::kw__Complex:
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2007-09-01 00:11:31 +08:00
|
|
|
/// property-attrlist: one of
|
|
|
|
/// readonly getter setter assign retain copy nonatomic
|
|
|
|
///
|
|
|
|
bool Parser::isObjCPropertyAttribute() {
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
2007-09-01 00:11:31 +08:00
|
|
|
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
|
|
|
for (unsigned i = 0; i < objc_NumAttrs; ++i)
|
|
|
|
if (II == ObjcPropertyAttrs[i]) return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-08-23 00:35:03 +08:00
|
|
|
/// objc-type-name:
|
|
|
|
/// '(' objc-type-qualifiers[opt] type-name ')'
|
|
|
|
/// '(' objc-type-qualifiers[opt] ')'
|
|
|
|
///
|
|
|
|
/// objc-type-qualifiers:
|
|
|
|
/// objc-type-qualifier
|
|
|
|
/// objc-type-qualifiers objc-type-qualifier
|
|
|
|
///
|
2007-11-01 07:53:01 +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
|
|
|
|
|
|
|
SourceLocation LParenLoc = ConsumeParen(), RParenLoc;
|
2007-09-27 23:15:46 +08:00
|
|
|
TypeTy *Ty = 0;
|
2007-08-23 00:35:03 +08:00
|
|
|
|
2007-11-01 05:59:43 +08:00
|
|
|
// Parse type qualifiers, in, inout, etc.
|
|
|
|
ParseObjcTypeQualifierList(DS);
|
2007-08-23 07:18:22 +08:00
|
|
|
|
2007-08-23 00:35:03 +08:00
|
|
|
if (isTypeSpecifierQualifier()) {
|
2007-09-06 07:30:30 +08:00
|
|
|
Ty = ParseTypeName();
|
|
|
|
// FIXME: back when Sema support is in place...
|
|
|
|
// assert(Ty && "Parser::ParseObjCTypeName(): missing type");
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2007-08-23 00:35:03 +08:00
|
|
|
MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2007-09-06 07:30:30 +08:00
|
|
|
return 0; // FIXME: decide how we want to handle this error...
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
RParenLoc = ConsumeParen();
|
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,
|
|
|
|
tok::TokenKind mType,
|
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
|
|
|
tok::ObjCKeywordKind MethodImplKind)
|
|
|
|
{
|
2007-08-23 02:35:33 +08:00
|
|
|
// Parse the return type.
|
2007-10-07 10:00:24 +08:00
|
|
|
TypeTy *ReturnType = 0;
|
2007-11-01 07:53:01 +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);
|
2007-10-27 04:53:56 +08:00
|
|
|
SourceLocation selLoc;
|
|
|
|
IdentifierInfo *SelIdent = ParseObjCSelector(selLoc);
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::colon)) {
|
2007-10-07 10:00:24 +08:00
|
|
|
if (!SelIdent) {
|
|
|
|
Diag(Tok, diag::err_expected_ident); // missing selector name.
|
|
|
|
// FIXME: this creates a unary selector with a null identifier, is this
|
|
|
|
// ok?? Maybe we should skip to the next semicolon or something.
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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-01 07:53:01 +08:00
|
|
|
mType, DSRet, ReturnType, Sel,
|
|
|
|
0, 0, 0, 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;
|
2007-11-01 07:53:01 +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 ':'.
|
2007-11-01 07:53:01 +08:00
|
|
|
ObjcDeclSpec DSType;
|
|
|
|
if (Tok.is(tok::l_paren)) { // Parse the argument type.
|
|
|
|
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.
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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-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
|
|
|
// Parse the c-style argument declaration-specifier.
|
|
|
|
DeclSpec DS;
|
|
|
|
ParseDeclarationSpecifiers(DS);
|
|
|
|
// Parse the declarator.
|
|
|
|
Declarator ParmDecl(DS, Declarator::PrototypeContext);
|
|
|
|
ParseDeclarator(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-01 07:53:01 +08:00
|
|
|
mType, DSRet, ReturnType, Sel,
|
|
|
|
&ArgTypeQuals[0], &KeyTypes[0],
|
|
|
|
&ArgNames[0],
|
2007-10-07 10:00:24 +08:00
|
|
|
MethodAttrs, MethodImplKind);
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
2007-10-09 07:06:41 +08:00
|
|
|
/// CmpProtocolVals - Comparison predicate for sorting protocols.
|
|
|
|
static bool CmpProtocolVals(const IdentifierInfo* const& lhs,
|
|
|
|
const IdentifierInfo* const& rhs) {
|
|
|
|
return strcmp(lhs->getName(), rhs->getName()) < 0;
|
|
|
|
}
|
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-protocol-refs:
|
|
|
|
/// '<' identifier-list '>'
|
|
|
|
///
|
2007-09-06 07:30:30 +08:00
|
|
|
bool Parser::ParseObjCProtocolReferences(
|
2007-10-30 10:23:23 +08:00
|
|
|
llvm::SmallVectorImpl<IdentifierInfo*> &ProtocolRefs, SourceLocation &endLoc)
|
|
|
|
{
|
2007-10-10 01:51:17 +08:00
|
|
|
assert(Tok.is(tok::less) && "expected <");
|
2007-08-21 05:31:48 +08:00
|
|
|
|
|
|
|
ConsumeToken(); // the "<"
|
|
|
|
|
|
|
|
while (1) {
|
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);
|
|
|
|
SkipUntil(tok::greater);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
ProtocolRefs.push_back(Tok.getIdentifierInfo());
|
|
|
|
ConsumeToken();
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::comma))
|
2007-08-21 05:31:48 +08:00
|
|
|
break;
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
2007-10-09 07:06:41 +08:00
|
|
|
|
|
|
|
// Sort protocols, keyed by name.
|
|
|
|
// Later on, we remove duplicates.
|
|
|
|
std::stable_sort(ProtocolRefs.begin(), ProtocolRefs.end(), CmpProtocolVals);
|
|
|
|
|
|
|
|
// Make protocol names unique.
|
|
|
|
ProtocolRefs.erase(std::unique(ProtocolRefs.begin(), ProtocolRefs.end()),
|
|
|
|
ProtocolRefs.end());
|
2007-08-21 05:31:48 +08:00
|
|
|
// Consume the '>'.
|
2007-10-30 10:23:23 +08:00
|
|
|
if (Tok.is(tok::greater)) {
|
|
|
|
endLoc = ConsumeAnyToken();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Diag(Tok, diag::err_expected_greater);
|
|
|
|
return true;
|
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-07 05:24:23 +08:00
|
|
|
llvm::SmallVector<DeclTy*, 16> IvarDecls;
|
2007-09-14 04:56:13 +08:00
|
|
|
llvm::SmallVector<DeclTy*, 32> AllIvarDecls;
|
|
|
|
llvm::SmallVector<tok::ObjCKeywordKind, 32> AllVisibilities;
|
2007-08-22 05:17:12 +08:00
|
|
|
|
|
|
|
SourceLocation LBraceLoc = ConsumeBrace(); // the "{"
|
|
|
|
|
2007-09-14 04:56:13 +08:00
|
|
|
tok::ObjCKeywordKind visibility = tok::objc_private;
|
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;
|
|
|
|
}
|
|
|
|
// 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);
|
|
|
|
ConsumeToken();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ParseStructDeclaration(interfaceDecl, IvarDecls);
|
2007-09-14 04:56:13 +08:00
|
|
|
for (unsigned i = 0; i < IvarDecls.size(); i++) {
|
|
|
|
AllIvarDecls.push_back(IvarDecls[i]);
|
|
|
|
AllVisibilities.push_back(visibility);
|
|
|
|
}
|
2007-09-07 05:24:23 +08:00
|
|
|
IvarDecls.clear();
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2007-08-22 05:17:12 +08:00
|
|
|
ConsumeToken();
|
2007-10-10 01:51:17 +08:00
|
|
|
} else if (Tok.is(tok::r_brace)) {
|
2007-08-22 05:17:12 +08:00
|
|
|
Diag(Tok.getLocation(), diag::ext_expected_semi_decl_list);
|
|
|
|
break;
|
|
|
|
} 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(),
|
|
|
|
LBraceLoc, RBraceLoc, &AllVisibilities[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.
|
|
|
|
|
2007-08-23 06:17:26 +08:00
|
|
|
Parser::DeclTy *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc) {
|
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-09-21 23:40:54 +08:00
|
|
|
llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::semi)) { // forward declaration of one protocol.
|
2007-08-23 06:17:26 +08:00
|
|
|
ConsumeToken();
|
2007-09-21 23:40:54 +08:00
|
|
|
ProtocolRefs.push_back(protocolName);
|
2007-08-23 06:17:26 +08:00
|
|
|
}
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::comma)) { // list of forward declarations.
|
2007-08-23 06:17:26 +08:00
|
|
|
// Parse the list of forward declarations.
|
|
|
|
ProtocolRefs.push_back(protocolName);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
ProtocolRefs.push_back(Tok.getIdentifierInfo());
|
|
|
|
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;
|
|
|
|
}
|
2007-09-21 23:40:54 +08:00
|
|
|
if (ProtocolRefs.size() > 0)
|
2007-10-11 01:32:04 +08:00
|
|
|
return Actions.ActOnForwardProtocolDeclaration(AtLoc,
|
2007-10-03 06:39:18 +08:00
|
|
|
&ProtocolRefs[0],
|
|
|
|
ProtocolRefs.size());
|
2007-08-23 06:17:26 +08:00
|
|
|
// Last, and definitely not least, parse a protocol declaration.
|
2007-10-30 10:23:23 +08:00
|
|
|
SourceLocation endProtoLoc;
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::less)) {
|
2007-10-30 10:23:23 +08:00
|
|
|
if (ParseObjCProtocolReferences(ProtocolRefs, endProtoLoc))
|
2007-08-23 06:17:26 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2007-09-18 05:07:36 +08:00
|
|
|
|
2007-10-11 01:32:04 +08:00
|
|
|
DeclTy *ProtoType = Actions.ActOnStartProtocolInterface(AtLoc,
|
2007-09-18 05:07:36 +08:00
|
|
|
protocolName, nameLoc,
|
|
|
|
&ProtocolRefs[0],
|
2007-10-30 10:23:23 +08:00
|
|
|
ProtocolRefs.size(), endProtoLoc);
|
2007-09-18 05:07:36 +08:00
|
|
|
ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol);
|
2007-08-23 06:17:26 +08:00
|
|
|
|
|
|
|
// The @ sign was already consumed by ParseObjCInterfaceDeclList().
|
2007-08-24 02:16:40 +08:00
|
|
|
if (Tok.isObjCAtKeyword(tok::objc_end)) {
|
2007-08-23 06:17:26 +08:00
|
|
|
ConsumeToken(); // the "end" identifier
|
2007-10-09 02:53:38 +08:00
|
|
|
return ProtoType;
|
2007-08-23 06:17:26 +08:00
|
|
|
}
|
|
|
|
Diag(Tok, diag::err_objc_missing_end);
|
2007-08-21 05:31:48 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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);
|
|
|
|
return ImplCatType;
|
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-10-04 05:00:46 +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);
|
2007-09-01 08:26:16 +08:00
|
|
|
|
2007-09-28 02:57:03 +08:00
|
|
|
return ImplClsType;
|
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");
|
|
|
|
ConsumeToken(); // the "end" identifier
|
2007-09-28 02:57:03 +08:00
|
|
|
if (ObjcImpDecl) {
|
|
|
|
// Checking is not necessary except that a parse error might have caused
|
|
|
|
// @implementation not to have been parsed to completion and ObjcImpDecl
|
|
|
|
// could be 0.
|
|
|
|
/// Insert collected methods declarations into the @interface object.
|
2007-10-04 05:00:46 +08:00
|
|
|
Actions.ActOnAddMethodsToObjcDecl(CurScope, ObjcImpDecl,
|
2007-10-30 05:38:07 +08:00
|
|
|
&AllImplMethods[0], AllImplMethods.size(),
|
|
|
|
atLoc);
|
2007-09-28 02:57:03 +08:00
|
|
|
ObjcImpDecl = 0;
|
|
|
|
AllImplMethods.clear();
|
|
|
|
}
|
2007-09-01 08:26:16 +08:00
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
return 0;
|
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)) {
|
2007-09-05 05:42:12 +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'");
|
|
|
|
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)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
ConsumeToken(); // consume ivar-name
|
|
|
|
}
|
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))
|
2007-09-01 08:26:16 +08:00
|
|
|
Diag(Tok, diag::err_expected_semi_after, "@synthesize");
|
|
|
|
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)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
ConsumeToken(); // consume property name
|
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))
|
2007-09-01 08:26:16 +08:00
|
|
|
Diag(Tok, diag::err_expected_semi_after, "@dynamic");
|
|
|
|
return 0;
|
|
|
|
}
|
2007-09-20 03:14:32 +08:00
|
|
|
|
|
|
|
/// objc-throw-statement:
|
|
|
|
/// throw expression[opt];
|
|
|
|
///
|
2007-10-05 04:19:06 +08:00
|
|
|
Parser::DeclTy *Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
|
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-10-05 04:19:06 +08:00
|
|
|
ExprResult Res = ParseExpression();
|
2007-09-20 03:14:32 +08:00
|
|
|
if (Res.isInvalid) {
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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]
|
|
|
|
///
|
2007-11-02 05:12:44 +08:00
|
|
|
Parser::StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
|
2007-09-20 03:14:32 +08:00
|
|
|
bool catch_or_finally_seen = false;
|
|
|
|
ConsumeToken(); // consume try
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2007-09-20 03:14:32 +08:00
|
|
|
Diag (Tok, diag::err_expected_lbrace);
|
2007-11-02 05:12:44 +08:00
|
|
|
return true;
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
2007-11-02 07:59:59 +08:00
|
|
|
StmtResult CatchStmts;
|
2007-11-02 08:18:53 +08:00
|
|
|
StmtResult FinallyStmt;
|
2007-09-20 03:14:32 +08:00
|
|
|
StmtResult TryBody = ParseCompoundStatementBody();
|
2007-10-10 01:51:17 +08:00
|
|
|
while (Tok.is(tok::at)) {
|
2007-11-02 08:18:53 +08:00
|
|
|
SourceLocation AtCatchFinallyLoc = ConsumeToken();
|
2007-09-20 03:14:32 +08:00
|
|
|
if (Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_catch) {
|
2007-11-02 07:59:59 +08:00
|
|
|
StmtTy *FirstPart = 0;
|
|
|
|
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();
|
2007-11-02 07:59:59 +08:00
|
|
|
EnterScope(Scope::DeclScope);
|
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);
|
2007-11-02 07:59:59 +08:00
|
|
|
// FIXME: Is BlockContext right?
|
|
|
|
Declarator DeclaratorInfo(DS, Declarator::BlockContext);
|
|
|
|
ParseDeclarator(DeclaratorInfo);
|
|
|
|
StmtResult stmtResult = Actions.ActOnDeclarator(CurScope,
|
|
|
|
DeclaratorInfo, 0);
|
|
|
|
FirstPart = stmtResult.isInvalid ? 0 : stmtResult.Val;
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
ConsumeToken(); // consume '...'
|
2007-11-02 07:59:59 +08:00
|
|
|
SourceLocation RParenLoc = ConsumeParen();
|
2007-11-02 05:12:44 +08:00
|
|
|
StmtResult CatchBody = ParseCompoundStatementBody();
|
2007-11-02 07:59:59 +08:00
|
|
|
if (CatchBody.isInvalid)
|
|
|
|
CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
|
2007-11-02 08:18:53 +08:00
|
|
|
CatchStmts = Actions.ActOnObjcAtCatchStmt(AtCatchFinallyLoc, RParenLoc,
|
2007-11-02 07:59:59 +08:00
|
|
|
FirstPart, CatchBody.Val, CatchStmts.Val);
|
|
|
|
ExitScope();
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
|
|
|
else {
|
2007-11-02 08:18:53 +08:00
|
|
|
Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after,
|
|
|
|
"@catch clause");
|
2007-11-02 05:12:44 +08:00
|
|
|
return true;
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
|
|
|
catch_or_finally_seen = true;
|
|
|
|
}
|
|
|
|
else if (Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_finally) {
|
|
|
|
ConsumeToken(); // consume finally
|
|
|
|
StmtResult FinallyBody = ParseCompoundStatementBody();
|
2007-11-02 08:18:53 +08:00
|
|
|
if (FinallyBody.isInvalid)
|
|
|
|
FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());
|
|
|
|
FinallyStmt = Actions.ActOnObjcAtFinallyStmt(AtCatchFinallyLoc,
|
|
|
|
FinallyBody.Val);
|
2007-09-20 03:14:32 +08:00
|
|
|
catch_or_finally_seen = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!catch_or_finally_seen)
|
|
|
|
Diag(atLoc, diag::err_missing_catch_finally);
|
2007-11-02 05:12:44 +08:00
|
|
|
return true;
|
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-08-23 06:17:26 +08:00
|
|
|
void Parser::ParseObjCInstanceMethodDefinition() {
|
2007-10-10 01:51:17 +08:00
|
|
|
assert(Tok.is(tok::minus) && "Method definitions should start with '-'");
|
|
|
|
|
2007-09-18 05:07:36 +08:00
|
|
|
// FIXME: @optional/@protocol??
|
2007-09-28 02:57:03 +08:00
|
|
|
AllImplMethods.push_back(ParseObjCMethodPrototype(ObjcImpDecl));
|
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-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
Diag (Tok, diag::err_expected_lbrace);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
StmtResult FnBody = ParseCompoundStatementBody();
|
2006-11-05 10:08:13 +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-08-23 06:17:26 +08:00
|
|
|
void Parser::ParseObjCClassMethodDefinition() {
|
2007-10-10 01:51:17 +08:00
|
|
|
assert(Tok.is(tok::plus) && "Class method definitions should start with '+'");
|
2007-09-18 05:07:36 +08:00
|
|
|
// FIXME: @optional/@protocol??
|
2007-09-28 02:57:03 +08:00
|
|
|
AllImplMethods.push_back(ParseObjCMethodPrototype(ObjcImpDecl));
|
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-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
2007-09-01 08:26:16 +08:00
|
|
|
Diag (Tok, diag::err_expected_lbrace);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
StmtResult FnBody = ParseCompoundStatementBody();
|
2006-11-05 10:08:13 +08:00
|
|
|
}
|
2007-08-22 01:43:55 +08:00
|
|
|
|
2007-10-16 04:55:58 +08:00
|
|
|
Parser::ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
|
2007-08-22 01:43:55 +08:00
|
|
|
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
case tok::string_literal: // primary-expression: string-literal
|
|
|
|
case tok::wide_string_literal:
|
2007-10-05 04:19:06 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCStringLiteral());
|
2007-08-23 23:25:28 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
|
2007-10-17 06:51:17 +08:00
|
|
|
case tok::objc_encode:
|
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc));
|
|
|
|
case tok::objc_protocol:
|
2007-10-17 07:21:02 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc));
|
2007-10-17 06:51:17 +08:00
|
|
|
case tok::objc_selector:
|
2007-10-17 07:21:02 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc));
|
2007-10-17 06:51:17 +08:00
|
|
|
default:
|
|
|
|
Diag(AtLoc, diag::err_unexpected_at);
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
break;
|
2007-08-22 01:43:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-09-06 03:52:07 +08:00
|
|
|
/// objc-message-expr:
|
|
|
|
/// '[' objc-receiver objc-message-args ']'
|
|
|
|
///
|
|
|
|
/// objc-receiver:
|
|
|
|
/// expression
|
|
|
|
/// class-name
|
|
|
|
/// type-name
|
|
|
|
///
|
|
|
|
/// 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
|
|
|
|
///
|
|
|
|
Parser::ExprResult Parser::ParseObjCMessageExpression() {
|
2007-10-10 01:51:17 +08:00
|
|
|
assert(Tok.is(tok::l_square) && "'[' expected");
|
2007-09-19 07:55:05 +08:00
|
|
|
SourceLocation LBracloc = ConsumeBracket(); // consume '['
|
2007-09-18 04:25:27 +08:00
|
|
|
IdentifierInfo *ReceiverName = 0;
|
|
|
|
ExprTy *ReceiverExpr = 0;
|
2007-09-06 07:08:20 +08:00
|
|
|
// Parse receiver
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.is(tok::identifier) &&
|
2007-09-18 04:25:27 +08:00
|
|
|
Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) {
|
|
|
|
ReceiverName = Tok.getIdentifierInfo();
|
2007-09-17 00:16:00 +08:00
|
|
|
ConsumeToken();
|
2007-09-18 04:25:27 +08:00
|
|
|
} else {
|
|
|
|
ExprResult Res = ParseAssignmentExpression();
|
|
|
|
if (Res.isInvalid) {
|
|
|
|
SkipUntil(tok::identifier);
|
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
ReceiverExpr = Res.Val;
|
|
|
|
}
|
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
|
|
|
|
|
|
|
llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
|
|
|
|
llvm::SmallVector<Action::ExprTy *, 12> KeyExprs;
|
|
|
|
|
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);
|
|
|
|
SkipUntil(tok::semi);
|
2007-09-18 04:25:27 +08:00
|
|
|
return true;
|
2007-09-06 07:08:20 +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 ':'
|
2007-09-18 04:25:27 +08:00
|
|
|
ExprResult Res = ParseAssignmentExpression();
|
|
|
|
if (Res.isInvalid) {
|
|
|
|
SkipUntil(tok::identifier);
|
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
// We have a valid expression.
|
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
|
|
|
KeyExprs.push_back(Res.Val);
|
2007-09-06 07:08:20 +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-09-06 07:08:20 +08:00
|
|
|
ConsumeToken();
|
|
|
|
/// Parse the expression after ','
|
|
|
|
ParseAssignmentExpression();
|
|
|
|
}
|
|
|
|
} else if (!selIdent) {
|
|
|
|
Diag(Tok, diag::err_expected_ident); // missing selector name.
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return 0;
|
|
|
|
}
|
2007-10-07 10:00:24 +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);
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return 0;
|
|
|
|
}
|
2007-09-19 07:55:05 +08:00
|
|
|
SourceLocation RBracloc = ConsumeBracket(); // consume ']'
|
2007-09-18 04:25:27 +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]);
|
|
|
|
|
|
|
|
// We've just parsed a keyword message.
|
2007-09-18 04:25:27 +08:00
|
|
|
if (ReceiverName)
|
2007-10-07 10:00:24 +08:00
|
|
|
return Actions.ActOnClassMessage(ReceiverName, Sel, LBracloc, RBracloc,
|
|
|
|
&KeyExprs[0]);
|
|
|
|
return Actions.ActOnInstanceMessage(ReceiverExpr, Sel, LBracloc, RBracloc,
|
|
|
|
&KeyExprs[0]);
|
2007-09-06 03:52:07 +08:00
|
|
|
}
|
|
|
|
|
2007-08-22 01:43:55 +08:00
|
|
|
Parser::ExprResult Parser::ParseObjCStringLiteral() {
|
|
|
|
ExprResult Res = ParseStringLiteralExpression();
|
|
|
|
|
|
|
|
if (Res.isInvalid) return Res;
|
|
|
|
|
|
|
|
return Actions.ParseObjCStringLiteral(Res.Val);
|
|
|
|
}
|
2007-08-22 23:14:15 +08:00
|
|
|
|
|
|
|
/// objc-encode-expression:
|
|
|
|
/// @encode ( type-name )
|
2007-10-17 06:51:17 +08:00
|
|
|
Parser::ExprResult Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
|
2007-08-24 02:16:40 +08:00
|
|
|
assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
|
2007-08-22 23:14:15 +08:00
|
|
|
|
|
|
|
SourceLocation EncLoc = ConsumeToken();
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
2007-08-22 23:14:15 +08:00
|
|
|
Diag(Tok, diag::err_expected_lparen_after, "@encode");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation LParenLoc = ConsumeParen();
|
|
|
|
|
|
|
|
TypeTy *Ty = ParseTypeName();
|
|
|
|
|
2007-08-23 23:31:37 +08:00
|
|
|
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2007-08-22 23:14:15 +08:00
|
|
|
|
2007-10-17 06:51:17 +08:00
|
|
|
return Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, LParenLoc, Ty,
|
2007-08-23 23:31:37 +08:00
|
|
|
RParenLoc);
|
2007-08-22 23:14:15 +08:00
|
|
|
}
|
2007-08-23 23:25:28 +08:00
|
|
|
|
|
|
|
/// objc-protocol-expression
|
|
|
|
/// @protocol ( protocol-name )
|
|
|
|
|
2007-10-17 07:21:02 +08:00
|
|
|
Parser::ExprResult Parser::ParseObjCProtocolExpression(SourceLocation AtLoc)
|
2007-08-23 23:25:28 +08:00
|
|
|
{
|
|
|
|
SourceLocation ProtoLoc = ConsumeToken();
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
2007-08-23 23:25:28 +08:00
|
|
|
Diag(Tok, diag::err_expected_lparen_after, "@protocol");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation LParenLoc = ConsumeParen();
|
|
|
|
|
2007-10-10 01:51:17 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2007-08-23 23:25:28 +08:00
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
return true;
|
|
|
|
}
|
2007-10-18 00:58:11 +08:00
|
|
|
IdentifierInfo *protocolId = Tok.getIdentifierInfo();
|
2007-08-23 23:25:28 +08:00
|
|
|
ConsumeToken();
|
|
|
|
|
2007-08-23 23:31:37 +08:00
|
|
|
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2007-08-23 23:25:28 +08:00
|
|
|
|
2007-10-18 00:58:11 +08:00
|
|
|
return 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 ')'
|
2007-10-17 07:21:02 +08:00
|
|
|
Parser::ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc)
|
2007-10-16 07:39:13 +08:00
|
|
|
{
|
|
|
|
SourceLocation SelectorLoc = ConsumeToken();
|
|
|
|
|
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
|
|
|
Diag(Tok, diag::err_expected_lparen_after, "@selector");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
if (!SelIdent && Tok.isNot(tok::colon)) {
|
|
|
|
|
|
|
|
Diag(Tok, diag::err_expected_ident); // missing selector name.
|
|
|
|
return 0;
|
|
|
|
}
|
2007-10-17 04:40:23 +08:00
|
|
|
KeyIdents.push_back(SelIdent);
|
2007-10-16 07:39:13 +08:00
|
|
|
if (Tok.isNot(tok::r_paren))
|
|
|
|
while (1) {
|
|
|
|
if (Tok.isNot(tok::colon)) {
|
|
|
|
Diag(Tok, diag::err_expected_colon);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2007-10-17 04:40:23 +08:00
|
|
|
Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
|
|
|
|
&KeyIdents[0]);
|
2007-10-17 07:21:02 +08:00
|
|
|
return Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc, LParenLoc,
|
2007-10-17 04:40:23 +08:00
|
|
|
RParenLoc);
|
2007-10-19 23:38:32 +08:00
|
|
|
}
|