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"
|
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
|
|
|
|
/// [OBJC] objc-class-declaration [TODO]
|
|
|
|
/// [OBJC] objc-alias-declaration [TODO]
|
|
|
|
/// [OBJC] objc-protocol-definition [TODO]
|
|
|
|
/// [OBJC] objc-method-definition [TODO]
|
|
|
|
/// [OBJC] '@' 'end' [TODO]
|
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) {
|
|
|
|
if (Tok.getKind() != 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();
|
|
|
|
|
|
|
|
if (Tok.getKind() != tok::comma)
|
|
|
|
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-03 06:39:18 +08:00
|
|
|
return Actions.ActOnForwardClassDeclaration(CurScope, 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
|
|
|
|
|
|
|
|
if (Tok.getKind() != tok::identifier) {
|
|
|
|
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-08-24 03:56:30 +08:00
|
|
|
if (Tok.getKind() == 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-08-21 05:31:48 +08:00
|
|
|
if (Tok.getKind() == tok::identifier) {
|
|
|
|
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
|
|
|
}
|
|
|
|
if (Tok.getKind() != tok::r_paren) {
|
|
|
|
Diag(Tok, diag::err_expected_rparen);
|
|
|
|
SkipUntil(tok::r_paren, false); // don't stop at ';'
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
rparenLoc = ConsumeParen();
|
|
|
|
// Next, we need to check for any protocol references.
|
|
|
|
if (Tok.getKind() == tok::less) {
|
2007-09-06 07:30:30 +08:00
|
|
|
if (ParseObjCProtocolReferences(ProtocolRefs))
|
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-04 05:00:46 +08:00
|
|
|
DeclTy *CategoryType = Actions.ActOnStartCategoryInterface(CurScope, atLoc,
|
|
|
|
nameId, nameLoc, categoryId, categoryLoc,
|
|
|
|
&ProtocolRefs[0], ProtocolRefs.size());
|
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-08-21 05:31:48 +08:00
|
|
|
return 0;
|
|
|
|
}
|
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-08-21 05:31:48 +08:00
|
|
|
if (Tok.getKind() == tok::colon) { // a super class is specified.
|
|
|
|
ConsumeToken();
|
|
|
|
if (Tok.getKind() != tok::identifier) {
|
|
|
|
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-08-21 05:31:48 +08:00
|
|
|
if (Tok.getKind() == tok::less) {
|
2007-09-06 07:30:30 +08:00
|
|
|
if (ParseObjCProtocolReferences(ProtocolRefs))
|
2007-08-21 05:31:48 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2007-10-04 05:00:46 +08:00
|
|
|
DeclTy *ClsType = Actions.ActOnStartClassInterface(CurScope,
|
2007-09-26 02:38:09 +08:00
|
|
|
atLoc, nameId, nameLoc,
|
2007-09-06 07:30:30 +08:00
|
|
|
superClassId, superClassLoc, &ProtocolRefs[0],
|
|
|
|
ProtocolRefs.size(), attrList);
|
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
if (Tok.getKind() == tok::l_brace)
|
2007-09-07 05:24:23 +08:00
|
|
|
ParseObjCClassInstanceVariables(ClsType);
|
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-08-23 00:35:03 +08:00
|
|
|
while (1) {
|
|
|
|
if (Tok.getKind() == tok::at) {
|
|
|
|
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-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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) {
|
2007-09-18 08:25:23 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
if (Tok.getKind() == tok::semi)
|
|
|
|
ConsumeToken();
|
|
|
|
else if (Tok.getKind() == 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-09-11 04:33:04 +08:00
|
|
|
/// Insert collected methods declarations into the @interface object.
|
2007-10-04 05:00:46 +08:00
|
|
|
Actions.ActOnAddMethodsToObjcDecl(CurScope, interfaceDecl,
|
|
|
|
&allMethods[0], allMethods.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
|
|
|
|
///
|
|
|
|
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();
|
|
|
|
if (Tok.getKind() == tok::equal) {
|
|
|
|
loc = ConsumeToken();
|
|
|
|
if (Tok.getKind() == tok::identifier) {
|
|
|
|
if (II == ObjcPropertyAttrs[objc_setter]) {
|
|
|
|
loc = ConsumeToken(); // consume method name
|
|
|
|
if (Tok.getKind() != tok::colon) {
|
|
|
|
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
|
|
|
|
if (Tok.getKind() == tok::comma) {
|
|
|
|
loc = ConsumeToken();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (Tok.getKind() == tok::r_paren)
|
|
|
|
break;
|
|
|
|
Diag(loc, diag::err_expected_rparen);
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (Tok.getKind() == tok::r_paren)
|
|
|
|
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.
|
|
|
|
if (Tok.getKind() == tok::l_paren) {
|
|
|
|
// property has attribute list.
|
|
|
|
ParseObjCPropertyAttribute(0/*FIXME*/);
|
|
|
|
}
|
|
|
|
// Parse declaration portion of @property.
|
|
|
|
llvm::SmallVector<DeclTy*, 32> PropertyDecls;
|
|
|
|
ParseStructDeclaration(interfaceDecl, PropertyDecls);
|
|
|
|
if (Tok.getKind() == tok::semi)
|
|
|
|
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-08-23 00:35:03 +08:00
|
|
|
assert((Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) &&
|
|
|
|
"expected +/-");
|
|
|
|
|
|
|
|
tok::TokenKind methodType = Tok.getKind();
|
|
|
|
SourceLocation methodLoc = ConsumeToken();
|
|
|
|
|
2007-09-18 08:25:23 +08:00
|
|
|
DeclTy *MDecl = ParseObjCMethodDecl(methodType, methodLoc, 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
|
|
|
|
///
|
|
|
|
IdentifierInfo *Parser::ParseObjCSelector() {
|
|
|
|
tok::TokenKind tKind = Tok.getKind();
|
|
|
|
IdentifierInfo *II = 0;
|
2007-09-28 03:52:15 +08:00
|
|
|
switch (tKind) {
|
|
|
|
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:
|
|
|
|
II = Tok.getIdentifierInfo();
|
|
|
|
ConsumeToken();
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2007-08-23 00:35:03 +08:00
|
|
|
|
|
|
|
return II;
|
|
|
|
}
|
|
|
|
|
2007-08-23 07:18:22 +08:00
|
|
|
/// objc-type-qualifier: one of
|
|
|
|
/// in out inout bycopy byref oneway
|
|
|
|
///
|
|
|
|
bool Parser::isObjCTypeQualifier() {
|
|
|
|
if (Tok.getKind() == tok::identifier) {
|
2007-08-30 06:54:08 +08:00
|
|
|
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
|
|
|
for (unsigned i = 0; i < objc_NumQuals; ++i)
|
|
|
|
if (II == ObjcTypeQuals[i]) return true;
|
2007-08-23 07:18:22 +08:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-01 00:11:31 +08:00
|
|
|
/// property-attrlist: one of
|
|
|
|
/// readonly getter setter assign retain copy nonatomic
|
|
|
|
///
|
|
|
|
bool Parser::isObjCPropertyAttribute() {
|
|
|
|
if (Tok.getKind() == tok::identifier) {
|
|
|
|
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-09-06 07:30:30 +08:00
|
|
|
Parser::TypeTy *Parser::ParseObjCTypeName() {
|
2007-08-23 00:35:03 +08:00
|
|
|
assert(Tok.getKind() == tok::l_paren && "expected (");
|
|
|
|
|
|
|
|
SourceLocation LParenLoc = ConsumeParen(), RParenLoc;
|
2007-09-27 23:15:46 +08:00
|
|
|
TypeTy *Ty = 0;
|
2007-08-23 00:35:03 +08:00
|
|
|
|
2007-08-23 07:18:22 +08:00
|
|
|
while (isObjCTypeQualifier())
|
|
|
|
ConsumeToken();
|
|
|
|
|
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
|
|
|
}
|
|
|
|
if (Tok.getKind() != tok::r_paren) {
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2007-09-29 07:39:26 +08:00
|
|
|
unsigned Selector::getNumArgs() const {
|
|
|
|
unsigned IIF = getIdentifierInfoFlag();
|
|
|
|
if (IIF == ZeroArg)
|
|
|
|
return 0;
|
|
|
|
if (IIF == OneArg)
|
|
|
|
return 1;
|
|
|
|
// We point to a MultiKeywordSelector (pointer doesn't contain any flags).
|
|
|
|
MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
|
|
|
|
return SI->getNumArgs();
|
|
|
|
}
|
|
|
|
|
|
|
|
IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) {
|
|
|
|
IdentifierInfo *II = getAsIdentifierInfo();
|
|
|
|
if (II) {
|
|
|
|
assert(((argIndex == 0) || (argIndex == 1)) && "illegal keyword index");
|
|
|
|
return II;
|
|
|
|
}
|
|
|
|
// We point to a MultiKeywordSelector (pointer doesn't contain any flags).
|
|
|
|
MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
|
|
|
|
return SI->getIdentifierInfoForSlot(argIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *MultiKeywordSelector::getName(llvm::SmallVectorImpl<char> &methodName) {
|
|
|
|
methodName[0] = '\0';
|
|
|
|
keyword_iterator KeyIter = keyword_begin();
|
|
|
|
for (unsigned int i = 0; i < NumArgs; i++) {
|
|
|
|
if (KeyIter[i]) {
|
2007-10-02 10:01:22 +08:00
|
|
|
unsigned KeyLen = KeyIter[i]->getLength();
|
2007-09-29 07:39:26 +08:00
|
|
|
methodName.append(KeyIter[i]->getName(), KeyIter[i]->getName()+KeyLen);
|
|
|
|
}
|
|
|
|
methodName.push_back(':');
|
|
|
|
}
|
|
|
|
methodName.push_back('\0');
|
|
|
|
return &methodName[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
char *Selector::getName(llvm::SmallVectorImpl<char> &methodName) {
|
|
|
|
methodName[0] = '\0';
|
|
|
|
IdentifierInfo *II = getAsIdentifierInfo();
|
|
|
|
if (II) {
|
2007-10-02 10:01:22 +08:00
|
|
|
unsigned NameLen = II->getLength();
|
2007-09-29 07:39:26 +08:00
|
|
|
methodName.append(II->getName(), II->getName()+NameLen);
|
|
|
|
if (getNumArgs() == 1)
|
|
|
|
methodName.push_back(':');
|
|
|
|
methodName.push_back('\0');
|
|
|
|
} else { // We have a multiple keyword selector (no embedded flags).
|
|
|
|
MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
|
|
|
|
SI->getName(methodName);
|
|
|
|
}
|
|
|
|
return &methodName[0];
|
|
|
|
}
|
|
|
|
|
2007-09-29 06:22:11 +08:00
|
|
|
Selector Parser::ObjcGetUnarySelector(IdentifierInfo *unarySel)
|
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-09-29 06:22:11 +08:00
|
|
|
return Selector(unarySel, 0);
|
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-09-29 06:22:11 +08:00
|
|
|
Selector Parser::ObjcGetKeywordSelector(
|
|
|
|
llvm::SmallVectorImpl<IdentifierInfo *> &IIV)
|
|
|
|
{
|
|
|
|
if (IIV.size() == 1)
|
|
|
|
return Selector(IIV[0], 1);
|
|
|
|
|
|
|
|
llvm::FoldingSet<MultiKeywordSelector> &SelTab = PP.getSelectorTable();
|
|
|
|
|
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
|
|
|
// Unique selector, to guarantee there is one per name.
|
|
|
|
llvm::FoldingSetNodeID ID;
|
2007-09-29 06:22:11 +08:00
|
|
|
MultiKeywordSelector::Profile(ID, &IIV[0], IIV.size());
|
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
|
|
|
|
|
|
|
void *InsertPos = 0;
|
2007-09-29 06:22:11 +08:00
|
|
|
if (MultiKeywordSelector *SI = SelTab.FindNodeOrInsertPos(ID, InsertPos)) {
|
|
|
|
return Selector(SI);
|
|
|
|
}
|
|
|
|
// MultiKeywordSelector objects are not allocated with new because they have a
|
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
|
|
|
// variable size array (for parameter types) at the end of them.
|
2007-09-29 06:22:11 +08:00
|
|
|
MultiKeywordSelector *SI =
|
|
|
|
(MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) +
|
|
|
|
IIV.size()*sizeof(IdentifierInfo *));
|
|
|
|
new (SI) MultiKeywordSelector(IIV.size(), &IIV[0]);
|
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
|
|
|
SelTab.InsertNode(SI, InsertPos);
|
2007-09-29 06:22:11 +08:00
|
|
|
return Selector(SI);
|
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-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))
|
|
|
|
///
|
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
|
|
|
Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType,
|
|
|
|
SourceLocation mLoc,
|
|
|
|
tok::ObjCKeywordKind MethodImplKind)
|
|
|
|
{
|
2007-09-06 07:30:30 +08:00
|
|
|
TypeTy *ReturnType = 0;
|
2007-09-11 04:33:04 +08:00
|
|
|
AttributeList *methodAttrs = 0;
|
2007-09-06 07:30:30 +08:00
|
|
|
|
2007-08-23 02:35:33 +08:00
|
|
|
// Parse the return type.
|
2007-08-23 00:35:03 +08:00
|
|
|
if (Tok.getKind() == tok::l_paren)
|
2007-09-06 07:30:30 +08:00
|
|
|
ReturnType = ParseObjCTypeName();
|
2007-08-23 02:35:33 +08:00
|
|
|
IdentifierInfo *selIdent = ParseObjCSelector();
|
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;
|
|
|
|
llvm::SmallVector<IdentifierInfo *, 12> ArgNames;
|
|
|
|
|
2007-08-23 02:35:33 +08:00
|
|
|
if (Tok.getKind() == tok::colon) {
|
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
|
|
|
Action::TypeTy *TypeInfo;
|
2007-09-06 07:30:30 +08:00
|
|
|
|
2007-08-23 02:35:33 +08:00
|
|
|
while (1) {
|
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-06 07:30:30 +08:00
|
|
|
|
2007-08-23 02:35:33 +08:00
|
|
|
// Each iteration parses a single keyword argument.
|
|
|
|
if (Tok.getKind() != tok::colon) {
|
|
|
|
Diag(Tok, diag::err_expected_colon);
|
|
|
|
break;
|
|
|
|
}
|
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-08-23 02:35:33 +08:00
|
|
|
if (Tok.getKind() == tok::l_paren) // Parse the argument type.
|
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
|
|
|
TypeInfo = ParseObjCTypeName();
|
|
|
|
else
|
|
|
|
TypeInfo = 0;
|
|
|
|
KeyTypes.push_back(TypeInfo);
|
|
|
|
|
2007-08-23 06:17:26 +08:00
|
|
|
// If attributes exist before the argument name, parse them.
|
2007-08-24 03:56:30 +08:00
|
|
|
if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
|
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
|
|
|
ParseAttributes(); // FIXME: pass attributes through.
|
2007-08-23 06:17:26 +08:00
|
|
|
|
2007-08-23 02:35:33 +08:00
|
|
|
if (Tok.getKind() != tok::identifier) {
|
|
|
|
Diag(Tok, diag::err_expected_ident); // missing argument name.
|
|
|
|
break;
|
|
|
|
}
|
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
|
|
|
ArgNames.push_back(Tok.getIdentifierInfo());
|
2007-08-23 02:35:33 +08:00
|
|
|
ConsumeToken(); // Eat the identifier.
|
2007-09-06 07:30:30 +08:00
|
|
|
|
2007-09-18 04:25:27 +08:00
|
|
|
// Check for another keyword selector.
|
2007-09-06 07:30:30 +08:00
|
|
|
selIdent = ParseObjCSelector();
|
|
|
|
if (!selIdent && Tok.getKind() != tok::colon)
|
2007-08-23 02:35:33 +08:00
|
|
|
break;
|
|
|
|
// We have a selector or a colon, continue parsing.
|
|
|
|
}
|
|
|
|
// Parse the (optional) parameter list.
|
|
|
|
while (Tok.getKind() == tok::comma) {
|
|
|
|
ConsumeToken();
|
|
|
|
if (Tok.getKind() == tok::ellipsis) {
|
|
|
|
ConsumeToken();
|
|
|
|
break;
|
|
|
|
}
|
2007-09-06 03:52:07 +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-09-06 07:30:30 +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.
|
|
|
|
if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
|
|
|
|
methodAttrs = ParseAttributes();
|
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-09-29 06:22:11 +08:00
|
|
|
Selector Sel = ObjcGetKeywordSelector(KeyIdents);
|
2007-10-03 06:39:18 +08:00
|
|
|
return Actions.ActOnMethodDeclaration(mLoc, mType, ReturnType, Sel,
|
|
|
|
&KeyTypes[0], &ArgNames[0],
|
|
|
|
methodAttrs, MethodImplKind);
|
2007-08-23 02:35:33 +08:00
|
|
|
} else if (!selIdent) {
|
|
|
|
Diag(Tok, diag::err_expected_ident); // missing selector name.
|
|
|
|
}
|
2007-09-11 04:33:04 +08:00
|
|
|
// If attributes exist after the method, parse them.
|
|
|
|
if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
|
|
|
|
methodAttrs = ParseAttributes();
|
|
|
|
|
2007-09-29 06:22:11 +08:00
|
|
|
Selector Sel = ObjcGetUnarySelector(selIdent);
|
2007-10-03 06:39:18 +08:00
|
|
|
return Actions.ActOnMethodDeclaration(mLoc, mType, ReturnType, Sel,
|
|
|
|
0, 0, methodAttrs, MethodImplKind);
|
2007-08-23 00:35:03 +08:00
|
|
|
}
|
|
|
|
|
2007-08-21 05:31:48 +08:00
|
|
|
/// objc-protocol-refs:
|
|
|
|
/// '<' identifier-list '>'
|
|
|
|
///
|
2007-09-06 07:30:30 +08:00
|
|
|
bool Parser::ParseObjCProtocolReferences(
|
|
|
|
llvm::SmallVectorImpl<IdentifierInfo*> &ProtocolRefs) {
|
2007-08-21 05:31:48 +08:00
|
|
|
assert(Tok.getKind() == tok::less && "expected <");
|
|
|
|
|
|
|
|
ConsumeToken(); // the "<"
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (Tok.getKind() != tok::identifier) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
SkipUntil(tok::greater);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
ProtocolRefs.push_back(Tok.getIdentifierInfo());
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
if (Tok.getKind() != tok::comma)
|
|
|
|
break;
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
|
|
|
// Consume the '>'.
|
|
|
|
return ExpectAndConsume(tok::greater, diag::err_expected_greater);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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-09-07 05:24:23 +08:00
|
|
|
void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl) {
|
2007-08-22 05:17:12 +08:00
|
|
|
assert(Tok.getKind() == 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.
|
|
|
|
while (Tok.getKind() != tok::r_brace &&
|
|
|
|
Tok.getKind() != tok::eof) {
|
|
|
|
// Each iteration of this loop reads one objc-instance-variable-decl.
|
|
|
|
|
|
|
|
// Check for extraneous top-level semicolon.
|
|
|
|
if (Tok.getKind() == tok::semi) {
|
|
|
|
Diag(Tok, diag::ext_extra_struct_semi);
|
|
|
|
ConsumeToken();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Set the default visibility to private.
|
|
|
|
if (Tok.getKind() == tok::at) { // parse objc-visibility-spec
|
|
|
|
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-08-22 05:17:12 +08:00
|
|
|
if (Tok.getKind() == tok::semi) {
|
|
|
|
ConsumeToken();
|
|
|
|
} else if (Tok.getKind() == tok::r_brace) {
|
|
|
|
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-09-14 04:56:13 +08:00
|
|
|
if (AllIvarDecls.size()) { // Check for {} - no ivars in braces
|
2007-09-29 08:54:24 +08:00
|
|
|
Actions.ActOnFields(CurScope, LBraceLoc, interfaceDecl,
|
2007-09-16 02:49:24 +08:00
|
|
|
&AllIvarDecls[0], AllIvarDecls.size(),
|
|
|
|
&AllVisibilities[0]);
|
2007-09-14 04:56:13 +08:00
|
|
|
}
|
2007-08-22 05:17:12 +08:00
|
|
|
MatchRHSPunctuation(tok::r_brace, LBraceLoc);
|
|
|
|
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
|
|
|
|
|
|
|
|
if (Tok.getKind() != tok::identifier) {
|
|
|
|
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;
|
|
|
|
if (Tok.getKind() == 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
|
|
|
}
|
|
|
|
if (Tok.getKind() == tok::comma) { // list of forward declarations.
|
|
|
|
// Parse the list of forward declarations.
|
|
|
|
ProtocolRefs.push_back(protocolName);
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
ConsumeToken(); // the ','
|
|
|
|
if (Tok.getKind() != tok::identifier) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ProtocolRefs.push_back(Tok.getIdentifierInfo());
|
|
|
|
ConsumeToken(); // the identifier
|
|
|
|
|
|
|
|
if (Tok.getKind() != tok::comma)
|
|
|
|
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-03 06:39:18 +08:00
|
|
|
return Actions.ActOnForwardProtocolDeclaration(CurScope, AtLoc,
|
|
|
|
&ProtocolRefs[0],
|
|
|
|
ProtocolRefs.size());
|
2007-08-23 06:17:26 +08:00
|
|
|
// Last, and definitely not least, parse a protocol declaration.
|
|
|
|
if (Tok.getKind() == tok::less) {
|
2007-09-06 07:30:30 +08:00
|
|
|
if (ParseObjCProtocolReferences(ProtocolRefs))
|
2007-08-23 06:17:26 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2007-09-18 05:07:36 +08:00
|
|
|
|
2007-10-04 05:00:46 +08:00
|
|
|
DeclTy *ProtoType = Actions.ActOnStartProtocolInterface(CurScope, AtLoc,
|
2007-09-18 05:07:36 +08:00
|
|
|
protocolName, nameLoc,
|
|
|
|
&ProtocolRefs[0],
|
|
|
|
ProtocolRefs.size());
|
|
|
|
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
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
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
|
|
|
|
|
|
|
|
if (Tok.getKind() != tok::identifier) {
|
|
|
|
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
|
|
|
|
|
|
|
|
if (Tok.getKind() == tok::l_paren) {
|
|
|
|
// we have a category implementation.
|
|
|
|
SourceLocation lparenLoc = ConsumeParen();
|
|
|
|
SourceLocation categoryLoc, rparenLoc;
|
|
|
|
IdentifierInfo *categoryId = 0;
|
|
|
|
|
|
|
|
if (Tok.getKind() == tok::identifier) {
|
|
|
|
categoryId = Tok.getIdentifierInfo();
|
|
|
|
categoryLoc = ConsumeToken();
|
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_expected_ident); // missing category name.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (Tok.getKind() != tok::r_paren) {
|
|
|
|
Diag(Tok, diag::err_expected_rparen);
|
|
|
|
SkipUntil(tok::r_paren, false); // don't stop at ';'
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
rparenLoc = ConsumeParen();
|
2007-10-04 05:00:46 +08:00
|
|
|
DeclTy *ImplCatType = Actions.ActOnStartCategoryImplementation(CurScope,
|
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-09-01 08:26:16 +08:00
|
|
|
if (Tok.getKind() == tok::colon) {
|
|
|
|
// We have a super class
|
|
|
|
ConsumeToken();
|
|
|
|
if (Tok.getKind() != tok::identifier) {
|
|
|
|
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-04 05:00:46 +08:00
|
|
|
DeclTy *ImplClsType = Actions.ActOnStartClassImplementation(CurScope,
|
|
|
|
atLoc, nameId, nameLoc,
|
2007-09-26 02:38:09 +08:00
|
|
|
superClassId, superClassLoc);
|
|
|
|
|
2007-09-01 08:26:16 +08:00
|
|
|
if (Tok.getKind() == tok::l_brace)
|
2007-09-26 02:38:09 +08:00
|
|
|
ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/); // we have ivars
|
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-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,
|
|
|
|
&AllImplMethods[0],AllImplMethods.size());
|
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
|
|
|
|
if (Tok.getKind() != tok::identifier) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ConsumeToken(); // consume alias-name
|
|
|
|
if (Tok.getKind() != tok::identifier) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ConsumeToken(); // consume class-name;
|
|
|
|
if (Tok.getKind() != tok::semi)
|
2007-09-05 05:42:12 +08:00
|
|
|
Diag(Tok, diag::err_expected_semi_after, "@compatibility_alias");
|
2007-08-21 05:31:48 +08:00
|
|
|
return 0;
|
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
|
|
|
|
if (Tok.getKind() != tok::identifier) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
while (Tok.getKind() == tok::identifier) {
|
|
|
|
ConsumeToken(); // consume property name
|
|
|
|
if (Tok.getKind() == tok::equal) {
|
|
|
|
// property '=' ivar-name
|
|
|
|
ConsumeToken(); // consume '='
|
|
|
|
if (Tok.getKind() != tok::identifier) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ConsumeToken(); // consume ivar-name
|
|
|
|
}
|
|
|
|
if (Tok.getKind() != tok::comma)
|
|
|
|
break;
|
|
|
|
ConsumeToken(); // consume ','
|
|
|
|
}
|
|
|
|
if (Tok.getKind() != tok::semi)
|
|
|
|
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
|
|
|
|
if (Tok.getKind() != tok::identifier) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
while (Tok.getKind() == tok::identifier) {
|
|
|
|
ConsumeToken(); // consume property name
|
|
|
|
if (Tok.getKind() != tok::comma)
|
|
|
|
break;
|
|
|
|
ConsumeToken(); // consume ','
|
|
|
|
}
|
|
|
|
if (Tok.getKind() != tok::semi)
|
|
|
|
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
|
|
|
|
if (Tok.getKind() != 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-10-05 04:19:06 +08:00
|
|
|
Parser::DeclTy *Parser::ParseObjCTryStmt(SourceLocation atLoc) {
|
2007-09-20 03:14:32 +08:00
|
|
|
bool catch_or_finally_seen = false;
|
|
|
|
ConsumeToken(); // consume try
|
|
|
|
if (Tok.getKind() != tok::l_brace) {
|
|
|
|
Diag (Tok, diag::err_expected_lbrace);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
StmtResult TryBody = ParseCompoundStatementBody();
|
|
|
|
while (Tok.getKind() == tok::at) {
|
|
|
|
ConsumeToken();
|
|
|
|
if (Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_catch) {
|
|
|
|
SourceLocation catchLoc = ConsumeToken(); // consume catch
|
|
|
|
if (Tok.getKind() == tok::l_paren) {
|
|
|
|
ConsumeParen();
|
|
|
|
if (Tok.getKind() != tok::ellipsis) {
|
|
|
|
DeclSpec DS;
|
|
|
|
ParseDeclarationSpecifiers(DS);
|
|
|
|
// Parse the parameter-declaration.
|
|
|
|
// FIXME: BlockContext may not be the right context!
|
|
|
|
Declarator ParmDecl(DS, Declarator::BlockContext);
|
|
|
|
ParseDeclarator(ParmDecl);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ConsumeToken(); // consume '...'
|
|
|
|
ConsumeParen();
|
|
|
|
StmtResult CatchMody = ParseCompoundStatementBody();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Diag(catchLoc, diag::err_expected_lparen_after, "@catch clause");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
catch_or_finally_seen = true;
|
|
|
|
}
|
|
|
|
else if (Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_finally) {
|
|
|
|
ConsumeToken(); // consume finally
|
|
|
|
StmtResult FinallyBody = ParseCompoundStatementBody();
|
|
|
|
catch_or_finally_seen = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!catch_or_finally_seen)
|
|
|
|
Diag(atLoc, diag::err_missing_catch_finally);
|
|
|
|
return 0;
|
|
|
|
}
|
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-09-01 08:26:16 +08:00
|
|
|
assert(Tok.getKind() == tok::minus &&
|
|
|
|
"ParseObjCInstanceMethodDefinition(): Expected '-'");
|
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 ';'
|
|
|
|
if (Tok.getKind() == tok::semi)
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
if (Tok.getKind() != tok::l_brace) {
|
|
|
|
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-09-01 08:26:16 +08:00
|
|
|
assert(Tok.getKind() == tok::plus &&
|
|
|
|
"ParseObjCClassMethodDefinition(): Expected '+'");
|
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 ';'
|
|
|
|
if (Tok.getKind() == tok::semi)
|
|
|
|
ConsumeToken();
|
|
|
|
if (Tok.getKind() != tok::l_brace) {
|
|
|
|
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-05 04:19:06 +08:00
|
|
|
Parser::ExprResult Parser::ParseObjCExpression(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-08-22 23:14:15 +08:00
|
|
|
case tok::objc_encode:
|
2007-10-05 04:19:06 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression());
|
2007-08-23 23:25:28 +08:00
|
|
|
case tok::objc_protocol:
|
2007-10-05 04:19:06 +08:00
|
|
|
return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression());
|
2007-08-22 01:43:55 +08:00
|
|
|
default:
|
|
|
|
Diag(AtLoc, diag::err_unexpected_at);
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-09-06 07:08:20 +08:00
|
|
|
assert(Tok.getKind() == 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-09-17 00:16:00 +08:00
|
|
|
if (Tok.getKind() == 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
|
|
|
|
IdentifierInfo *selIdent = ParseObjCSelector();
|
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-09-06 07:08:20 +08:00
|
|
|
if (Tok.getKind() == tok::colon) {
|
|
|
|
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-09-06 07:08:20 +08:00
|
|
|
if (Tok.getKind() != tok::colon) {
|
|
|
|
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.
|
|
|
|
selIdent = ParseObjCSelector();
|
|
|
|
if (!selIdent && Tok.getKind() != 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.
|
|
|
|
while (Tok.getKind() == tok::comma) {
|
|
|
|
ConsumeToken();
|
|
|
|
/// Parse the expression after ','
|
|
|
|
ParseAssignmentExpression();
|
|
|
|
}
|
|
|
|
} else if (!selIdent) {
|
|
|
|
Diag(Tok, diag::err_expected_ident); // missing selector name.
|
|
|
|
SkipUntil(tok::semi);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (Tok.getKind() != tok::r_square) {
|
|
|
|
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
|
|
|
|
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
|
|
|
if (KeyIdents.size()) {
|
2007-09-29 06:22:11 +08:00
|
|
|
Selector sel = ObjcGetKeywordSelector(KeyIdents);
|
2007-09-18 05:01:15 +08:00
|
|
|
// We've just parsed a keyword message.
|
|
|
|
if (ReceiverName)
|
2007-09-29 06:22:11 +08:00
|
|
|
return Actions.ActOnClassMessage(ReceiverName, sel, LBracloc, RBracloc,
|
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[0]);
|
2007-09-29 06:22:11 +08:00
|
|
|
return Actions.ActOnInstanceMessage(ReceiverExpr, sel, LBracloc, RBracloc,
|
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[0]);
|
2007-09-18 05:01:15 +08:00
|
|
|
}
|
2007-09-29 06:22:11 +08:00
|
|
|
Selector sel = ObjcGetUnarySelector(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-09-18 05:01:15 +08:00
|
|
|
// We've just parsed a unary message (a message with no arguments).
|
2007-09-18 04:25:27 +08:00
|
|
|
if (ReceiverName)
|
2007-09-29 06:22:11 +08:00
|
|
|
return Actions.ActOnClassMessage(ReceiverName, sel, LBracloc, RBracloc, 0);
|
|
|
|
return Actions.ActOnInstanceMessage(ReceiverExpr, sel, LBracloc, RBracloc, 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 )
|
|
|
|
Parser::ExprResult Parser::ParseObjCEncodeExpression() {
|
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();
|
|
|
|
|
|
|
|
if (Tok.getKind() != tok::l_paren) {
|
|
|
|
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
|
|
|
|
|
|
|
return Actions.ParseObjCEncodeExpression(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 )
|
|
|
|
|
|
|
|
Parser::ExprResult Parser::ParseObjCProtocolExpression()
|
|
|
|
{
|
|
|
|
SourceLocation ProtoLoc = ConsumeToken();
|
|
|
|
|
|
|
|
if (Tok.getKind() != tok::l_paren) {
|
|
|
|
Diag(Tok, diag::err_expected_lparen_after, "@protocol");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation LParenLoc = ConsumeParen();
|
|
|
|
|
|
|
|
if (Tok.getKind() != tok::identifier) {
|
|
|
|
Diag(Tok, diag::err_expected_ident);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Do something with the protocol name
|
|
|
|
ConsumeToken();
|
|
|
|
|
2007-08-23 23:31:37 +08:00
|
|
|
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
2007-08-23 23:25:28 +08:00
|
|
|
|
|
|
|
// FIXME
|
|
|
|
return 0;
|
|
|
|
}
|