Add support for parsing method prototypes (and other stuff required by @interface).

Still need to finish Parser::ParseObjCMethodDecl(). Before I do, I need to do a minor
refactoring of ParseDeclarationOrFunctionDefinition(), to disallow function definitions.
At the moment, @inteface allows function defs (which is incorrect).

llvm-svn: 41275
This commit is contained in:
Steve Naroff 2007-08-22 16:35:03 +00:00
parent de979aeff3
commit 99264b4b04
4 changed files with 172 additions and 23 deletions

View File

@ -120,7 +120,7 @@ Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration(
return 0;
}
// We have a class or category name - consume it.
IdentifierInfo *nameId = Tok.getIdentifierInfo();
// IdentifierInfo *nameId = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken();
if (Tok.getKind() == tok::l_paren) { // we have a category
@ -147,18 +147,15 @@ Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration(
if (attrList) // categories don't support attributes.
Diag(Tok, diag::err_objc_no_attributes_on_category);
//ParseObjCInterfaceDeclList();
ParseObjCInterfaceDeclList(0/*FIXME*/);
if (Tok.getKind() != tok::at) { // check for @end
Diag(Tok, diag::err_objc_missing_end);
// The @ sign was already consumed by ParseObjCInterfaceDeclList().
if (Tok.getKind() == tok::identifier &&
Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_end) {
ConsumeToken(); // the "end" identifier
return 0;
}
SourceLocation atEndLoc = ConsumeToken(); // eat the @ sign
if (Tok.getIdentifierInfo()->getObjCKeywordID() != tok::objc_end) {
Diag(Tok, diag::err_objc_missing_end);
return 0;
}
ConsumeToken(); // the "end" identifier
Diag(Tok, diag::err_objc_missing_end);
return 0;
}
// Parse a class interface.
@ -183,32 +180,173 @@ Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration(
if (Tok.getKind() == tok::l_brace)
ParseObjCClassInstanceVariables(0/*FIXME*/);
//ParseObjCInterfaceDeclList();
if (Tok.getKind() != tok::at) { // check for @end
Diag(Tok, diag::err_objc_missing_end);
ParseObjCInterfaceDeclList(0/*FIXME*/);
// The @ sign was already consumed by ParseObjCInterfaceDeclList().
if (Tok.getKind() == tok::identifier &&
Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_end) {
ConsumeToken(); // the "end" identifier
return 0;
}
SourceLocation atEndLoc = ConsumeToken(); // eat the @ sign
if (Tok.getIdentifierInfo()->getObjCKeywordID() != tok::objc_end) {
Diag(Tok, diag::err_objc_missing_end);
return 0;
}
ConsumeToken(); // the "end" identifier
Diag(Tok, diag::err_objc_missing_end);
return 0;
}
/// objc-interface-decl-list:
/// empty
/// objc-interface-decl-list objc-method-proto
/// objc-interface-decl-list objc-property-decl [OBJC2]
/// objc-interface-decl-list objc-method-requirement [OBJC2]
/// objc-interface-decl-list objc-method-proto
/// objc-interface-decl-list declaration
/// objc-interface-decl-list ';'
///
void Parser::ParseObjCInterfaceDeclList() {
/// objc-method-requirement: [OBJC2]
/// @required
/// @optional
///
void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl) {
while (1) {
if (Tok.getKind() == tok::at) {
SourceLocation AtLoc = ConsumeToken(); // the "@"
tok::ObjCKeywordKind ocKind = Tok.getIdentifierInfo()->getObjCKeywordID();
if (ocKind == tok::objc_end) { // terminate list
return;
} else if (ocKind == tok::objc_required) { // protocols only
ConsumeToken();
continue;
} else if (ocKind == tok::objc_optional) { // protocols only
ConsumeToken();
continue;
} else if (ocKind == tok::objc_property) {
ParseObjCPropertyDecl(AtLoc);
continue;
} else {
Diag(Tok, diag::err_objc_illegal_interface_qual);
ConsumeToken();
}
}
if (Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) {
ParseObjCMethodPrototype();
continue;
}
if (Tok.getKind() == tok::semi)
ConsumeToken();
else if (Tok.getKind() == tok::eof)
return;
else
ParseDeclarationOrFunctionDefinition();
}
}
void Parser::ParseObjCPropertyDecl(SourceLocation atLoc) {
assert(0 && "Unimp");
}
/// objc-methodproto:
/// objc-instance-method objc-method-decl ';'
/// objc-class-method objc-method-decl ';'
///
/// objc-instance-method: '-'
/// objc-class-method: '+'
///
void Parser::ParseObjCMethodPrototype() {
assert((Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) &&
"expected +/-");
tok::TokenKind methodType = Tok.getKind();
SourceLocation methodLoc = ConsumeToken();
// FIXME: deal with "context sensitive" protocol qualifiers in prototypes
ParseObjCMethodDecl(methodType, methodLoc);
// Consume the ';'.
ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "method proto");
}
/// 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;
if (tKind == tok::identifier ||
(tKind >= tok::kw_auto && tKind <= tok::kw__Complex)) {
// FIXME: make sure the list of keywords jives with gcc. For example,
// the above test does not include in/out/inout/bycopy/byref/oneway.
II = Tok.getIdentifierInfo();
ConsumeToken();
}
return II;
}
/// 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
///
/// objc-type-qualifier: one of
/// in out inout bycopy byref oneway
///
void Parser::ParseObjCTypeName() {
assert(Tok.getKind() == tok::l_paren && "expected (");
SourceLocation LParenLoc = ConsumeParen(), RParenLoc;
if (isTypeSpecifierQualifier()) {
TypeTy *Ty = ParseTypeName();
assert(Ty && "Parser::ParseObjCTypeName(): missing type");
}
if (Tok.getKind() != tok::r_paren) {
MatchRHSPunctuation(tok::r_paren, LParenLoc);
return;
}
RParenLoc = ConsumeParen();
}
/// objc-method-decl:
/// objc-selector
/// objc-keyword-selector objc-optparmlist
/// objc-type-name objc-selector
/// objc-type-name objc-keyword-selector objc-optparmlist
///
/// objc-keyword-selector:
/// objc-keyword-decl
/// objc-keyword-selector objc-keyword-decl
///
/// objc-keyword-decl:
/// objc-selector ':' objc-type-name identifier
/// objc-selector ':' identifier
/// ':' objc-type-name identifier
/// ':' identifier
///
/// objc-optparmlist:
/// objc-optparms objc-optellipsis
///
/// objc-optparms:
/// empty
/// objc-opt-parms , parameter-declaration
///
/// objc-optellipsis:
/// empty
/// , ...
///
void Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc) {
if (Tok.getKind() == tok::l_paren)
ParseObjCTypeName();
ParseObjCSelector();
}
/// objc-protocol-refs:
/// '<' identifier-list '>'
///

View File

@ -384,6 +384,8 @@ DIAG(err_objc_missing_end, ERROR,
"missing @end")
DIAG(err_objc_illegal_visibility_spec, ERROR,
"illegal visibility specification")
DIAG(err_objc_illegal_interface_qual, ERROR,
"illegal interface qualifier")
//===----------------------------------------------------------------------===//
// Semantic Analysis

View File

@ -350,6 +350,8 @@ OBJC1_AT_KEYWORD(synchronized)
// I'm guessing this is an objc2 keyword, what are the others?
OBJC2_AT_KEYWORD(property)
OBJC2_AT_KEYWORD(package)
OBJC2_AT_KEYWORD(required)
OBJC2_AT_KEYWORD(optional)
// TODO: What to do about context-sensitive keywords like:
// bycopy/byref/in/inout/oneway/out?

View File

@ -260,12 +260,19 @@ private:
AttributeList *prefixAttrs = 0);
void ParseObjCClassInstanceVariables(DeclTy *interfaceDecl);
bool ParseObjCProtocolReferences();
void ParseObjCInterfaceDeclList();
void ParseObjCInterfaceDeclList(DeclTy *interfaceDecl);
DeclTy *ParseObjCAtProtocolDeclaration();
DeclTy *ParseObjCAtImplementationDeclaration();
DeclTy *ParseObjCAtEndDeclaration();
DeclTy *ParseObjCAtAliasDeclaration();
IdentifierInfo *ParseObjCSelector();
void ParseObjCTypeName();
void ParseObjCMethodRequirement();
void ParseObjCMethodPrototype();
void ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc);
void ParseObjCPropertyDecl(SourceLocation atLoc);
void ParseObjCInstanceMethodDeclaration();
void ParseObjCClassMethodDeclaration();