#include "clang/Parse/Parser.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "AstGuard.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "llvm/ADT/SmallVector.h"
using namespace clang;
Parser::DeclPtrTy Parser::ParseObjCAtDirectives() {
SourceLocation AtLoc = ConsumeToken();
switch (Tok.getObjCKeywordID()) {
case tok::objc_class:
return ParseObjCAtClassDeclaration(AtLoc);
case tok::objc_interface:
return ParseObjCAtInterfaceDeclaration(AtLoc);
case tok::objc_protocol:
return ParseObjCAtProtocolDeclaration(AtLoc);
case tok::objc_implementation:
return ParseObjCAtImplementationDeclaration(AtLoc);
case tok::objc_end:
return ParseObjCAtEndDeclaration(AtLoc);
case tok::objc_compatibility_alias:
return ParseObjCAtAliasDeclaration(AtLoc);
case tok::objc_synthesize:
return ParseObjCPropertySynthesize(AtLoc);
case tok::objc_dynamic:
return ParseObjCPropertyDynamic(AtLoc);
default:
Diag(AtLoc, diag::err_unexpected_at);
SkipUntil(tok::semi);
return DeclPtrTy();
}
}
Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
ConsumeToken(); llvm::SmallVector<IdentifierInfo *, 8> ClassNames;
while (1) {
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
SkipUntil(tok::semi);
return DeclPtrTy();
}
ClassNames.push_back(Tok.getIdentifierInfo());
ConsumeToken();
if (Tok.isNot(tok::comma))
break;
ConsumeToken();
}
if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
return DeclPtrTy();
return Actions.ActOnForwardClassDeclaration(atLoc,
&ClassNames[0], ClassNames.size());
}
Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
SourceLocation atLoc, AttributeList *attrList) {
assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
"ParseObjCAtInterfaceDeclaration(): Expected @interface");
ConsumeToken();
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); return DeclPtrTy();
}
IdentifierInfo *nameId = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken();
if (Tok.is(tok::l_paren)) { SourceLocation lparenLoc = ConsumeParen();
SourceLocation categoryLoc, rparenLoc;
IdentifierInfo *categoryId = 0;
if (Tok.is(tok::identifier)) {
categoryId = Tok.getIdentifierInfo();
categoryLoc = ConsumeToken();
} else if (!getLang().ObjC2) {
Diag(Tok, diag::err_expected_ident); return DeclPtrTy();
}
if (Tok.isNot(tok::r_paren)) {
Diag(Tok, diag::err_expected_rparen);
SkipUntil(tok::r_paren, false); return DeclPtrTy();
}
rparenLoc = ConsumeParen();
SourceLocation EndProtoLoc;
llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc))
return DeclPtrTy();
if (attrList) Diag(Tok, diag::err_objc_no_attributes_on_category);
DeclPtrTy CategoryType = Actions.ActOnStartCategoryInterface(atLoc,
nameId, nameLoc, categoryId, categoryLoc,
&ProtocolRefs[0], ProtocolRefs.size(),
EndProtoLoc);
ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword);
return CategoryType;
}
IdentifierInfo *superClassId = 0;
SourceLocation superClassLoc;
if (Tok.is(tok::colon)) { ConsumeToken();
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); return DeclPtrTy();
}
superClassId = Tok.getIdentifierInfo();
superClassLoc = ConsumeToken();
}
llvm::SmallVector<Action::DeclPtrTy, 8> ProtocolRefs;
SourceLocation EndProtoLoc;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, true, EndProtoLoc))
return DeclPtrTy();
DeclPtrTy ClsType =
Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc,
superClassId, superClassLoc,
&ProtocolRefs[0], ProtocolRefs.size(),
EndProtoLoc, attrList);
if (Tok.is(tok::l_brace))
ParseObjCClassInstanceVariables(ClsType, atLoc);
ParseObjCInterfaceDeclList(ClsType, tok::objc_interface);
return ClsType;
}
void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl,
tok::ObjCKeywordKind contextKey) {
llvm::SmallVector<DeclPtrTy, 32> allMethods;
llvm::SmallVector<DeclPtrTy, 16> allProperties;
llvm::SmallVector<DeclGroupPtrTy, 8> allTUVariables;
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword;
SourceLocation AtEndLoc;
while (1) {
if (Tok.is(tok::minus) || Tok.is(tok::plus)) {
DeclPtrTy methodPrototype =
ParseObjCMethodPrototype(interfaceDecl, MethodImplKind);
allMethods.push_back(methodPrototype);
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_method_proto,
"", tok::semi);
continue;
}
if (Tok.is(tok::semi)) {
ConsumeToken();
continue;
}
if (Tok.is(tok::eof))
break;
if (Tok.isNot(tok::at)) {
if (Tok.is(tok::r_brace))
break;
allTUVariables.push_back(ParseDeclarationOrFunctionDefinition());
continue;
}
SourceLocation AtLoc = ConsumeToken(); tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID();
if (DirectiveKind == tok::objc_end) { AtEndLoc = AtLoc;
break;
}
ConsumeToken();
switch (DirectiveKind) {
default:
Diag(AtLoc, diag::err_objc_illegal_interface_qual);
SkipUntil(tok::r_brace, tok::at);
break;
case tok::objc_required:
case tok::objc_optional:
if (contextKey != tok::objc_protocol)
Diag(AtLoc, diag::err_objc_directive_only_in_protocol);
else
MethodImplKind = DirectiveKind;
break;
case tok::objc_property:
if (!getLang().ObjC2)
Diag(AtLoc, diag::err_objc_propertoes_require_objc2);
ObjCDeclSpec OCDS;
if (Tok.is(tok::l_paren))
ParseObjCPropertyAttribute(OCDS);
DeclSpec DS;
llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators;
ParseStructDeclaration(DS, FieldDeclarators);
ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list, "",
tok::at);
for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) {
FieldDeclarator &FD = FieldDeclarators[i];
if (FD.D.getIdentifier() == 0) {
Diag(AtLoc, diag::err_objc_property_requires_field_name)
<< FD.D.getSourceRange();
continue;
}
if (FD.BitfieldSize) {
Diag(AtLoc, diag::err_objc_property_bitfield)
<< FD.D.getSourceRange();
continue;
}
IdentifierInfo *SelName =
OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
Selector GetterSel =
PP.getSelectorTable().getNullarySelector(SelName);
IdentifierInfo *SetterName = OCDS.getSetterName();
Selector SetterSel;
if (SetterName)
SetterSel = PP.getSelectorTable().getSelector(1, &SetterName);
else
SetterSel = SelectorTable::constructSetterName(PP.getIdentifierTable(),
PP.getSelectorTable(),
FD.D.getIdentifier());
bool isOverridingProperty = false;
DeclPtrTy Property = Actions.ActOnProperty(CurScope, AtLoc, FD, OCDS,
GetterSel, SetterSel,
interfaceDecl,
&isOverridingProperty,
MethodImplKind);
if (!isOverridingProperty)
allProperties.push_back(Property);
}
break;
}
}
if (Tok.isObjCAtKeyword(tok::objc_end))
ConsumeToken(); else
Diag(Tok, diag::err_objc_missing_end);
Actions.ActOnAtEnd(AtEndLoc, interfaceDecl,
&allMethods[0], allMethods.size(),
&allProperties[0], allProperties.size(),
&allTUVariables[0], allTUVariables.size());
}
void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
assert(Tok.getKind() == tok::l_paren);
SourceLocation LHSLoc = ConsumeParen();
while (1) {
const IdentifierInfo *II = Tok.getIdentifierInfo();
if (II == 0) {
MatchRHSPunctuation(tok::r_paren, LHSLoc);
return;
}
SourceLocation AttrName = ConsumeToken();
if (II->isStr("readonly"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readonly);
else if (II->isStr("assign"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_assign);
else if (II->isStr("readwrite"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readwrite);
else if (II->isStr("retain"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_retain);
else if (II->isStr("copy"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy);
else if (II->isStr("nonatomic"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic);
else if (II->isStr("getter") || II->isStr("setter")) {
if (ExpectAndConsume(tok::equal, diag::err_objc_expected_equal, "",
tok::r_paren))
return;
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
SkipUntil(tok::r_paren);
return;
}
if (II->getName()[0] == 's') {
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter);
DS.setSetterName(Tok.getIdentifierInfo());
ConsumeToken();
if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "",
tok::r_paren))
return;
} else {
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter);
DS.setGetterName(Tok.getIdentifierInfo());
ConsumeToken(); }
} else {
Diag(AttrName, diag::err_objc_expected_property_attr) << II;
SkipUntil(tok::r_paren);
return;
}
if (Tok.isNot(tok::comma))
break;
ConsumeToken();
}
MatchRHSPunctuation(tok::r_paren, LHSLoc);
}
Parser::DeclPtrTy Parser::ParseObjCMethodPrototype(DeclPtrTy IDecl,
tok::ObjCKeywordKind MethodImplKind) {
assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-");
tok::TokenKind methodType = Tok.getKind();
SourceLocation mLoc = ConsumeToken();
DeclPtrTy MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl,MethodImplKind);
return MDecl;
}
IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
switch (Tok.getKind()) {
default:
return 0;
case tok::identifier:
case tok::kw_asm:
case tok::kw_auto:
case tok::kw_bool:
case tok::kw_break:
case tok::kw_case:
case tok::kw_catch:
case tok::kw_char:
case tok::kw_class:
case tok::kw_const:
case tok::kw_const_cast:
case tok::kw_continue:
case tok::kw_default:
case tok::kw_delete:
case tok::kw_do:
case tok::kw_double:
case tok::kw_dynamic_cast:
case tok::kw_else:
case tok::kw_enum:
case tok::kw_explicit:
case tok::kw_export:
case tok::kw_extern:
case tok::kw_false:
case tok::kw_float:
case tok::kw_for:
case tok::kw_friend:
case tok::kw_goto:
case tok::kw_if:
case tok::kw_inline:
case tok::kw_int:
case tok::kw_long:
case tok::kw_mutable:
case tok::kw_namespace:
case tok::kw_new:
case tok::kw_operator:
case tok::kw_private:
case tok::kw_protected:
case tok::kw_public:
case tok::kw_register:
case tok::kw_reinterpret_cast:
case tok::kw_restrict:
case tok::kw_return:
case tok::kw_short:
case tok::kw_signed:
case tok::kw_sizeof:
case tok::kw_static:
case tok::kw_static_cast:
case tok::kw_struct:
case tok::kw_switch:
case tok::kw_template:
case tok::kw_this:
case tok::kw_throw:
case tok::kw_true:
case tok::kw_try:
case tok::kw_typedef:
case tok::kw_typeid:
case tok::kw_typename:
case tok::kw_typeof:
case tok::kw_union:
case tok::kw_unsigned:
case tok::kw_using:
case tok::kw_virtual:
case tok::kw_void:
case tok::kw_volatile:
case tok::kw_wchar_t:
case tok::kw_while:
case tok::kw__Bool:
case tok::kw__Complex:
case tok::kw___alignof:
IdentifierInfo *II = Tok.getIdentifierInfo();
SelectorLoc = ConsumeToken();
return II;
}
}
bool Parser::isTokIdentifier_in() const {
return (getLang().ObjC2 && Tok.is(tok::identifier) &&
Tok.getIdentifierInfo() == ObjCTypeQuals[objc_in]);
}
void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) {
while (1) {
if (Tok.isNot(tok::identifier))
return;
const IdentifierInfo *II = Tok.getIdentifierInfo();
for (unsigned i = 0; i != objc_NumQuals; ++i) {
if (II != ObjCTypeQuals[i])
continue;
ObjCDeclSpec::ObjCDeclQualifier Qual;
switch (i) {
default: assert(0 && "Unknown decl qualifier");
case objc_in: Qual = ObjCDeclSpec::DQ_In; break;
case objc_out: Qual = ObjCDeclSpec::DQ_Out; break;
case objc_inout: Qual = ObjCDeclSpec::DQ_Inout; break;
case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break;
case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break;
case objc_byref: Qual = ObjCDeclSpec::DQ_Byref; break;
}
DS.setObjCDeclQualifier(Qual);
ConsumeToken();
II = 0;
break;
}
if (II) return;
}
}
Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) {
assert(Tok.is(tok::l_paren) && "expected (");
SourceLocation LParenLoc = ConsumeParen();
SourceLocation TypeStartLoc = Tok.getLocation();
ParseObjCTypeQualifierList(DS);
TypeTy *Ty = 0;
if (isTypeSpecifierQualifier()) {
TypeResult TypeSpec = ParseTypeName();
if (!TypeSpec.isInvalid())
Ty = TypeSpec.get();
}
if (Tok.is(tok::r_paren))
ConsumeParen();
else if (Tok.getLocation() == TypeStartLoc) {
Diag(Tok, diag::err_expected_type);
SkipUntil(tok::r_paren);
} else {
MatchRHSPunctuation(tok::r_paren, LParenLoc);
}
return Ty;
}
Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc,
tok::TokenKind mType,
DeclPtrTy IDecl,
tok::ObjCKeywordKind MethodImplKind) {
TypeTy *ReturnType = 0;
ObjCDeclSpec DSRet;
if (Tok.is(tok::l_paren))
ReturnType = ParseObjCTypeName(DSRet);
SourceLocation selLoc;
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);
if (!SelIdent && Tok.isNot(tok::colon)) { Diag(Tok, diag::err_expected_selector_for_method)
<< SourceRange(mLoc, Tok.getLocation());
SkipUntil(tok::r_brace);
return DeclPtrTy();
}
llvm::SmallVector<Declarator, 8> CargNames;
if (Tok.isNot(tok::colon)) {
AttributeList *MethodAttrs = 0;
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
MethodAttrs = ParseAttributes();
Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
mType, IDecl, DSRet, ReturnType, Sel,
0, CargNames, MethodAttrs,
MethodImplKind);
}
llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
llvm::SmallVector<Action::ObjCArgInfo, 12> ArgInfos;
while (1) {
Action::ObjCArgInfo ArgInfo;
if (Tok.isNot(tok::colon)) {
Diag(Tok, diag::err_expected_colon);
break;
}
ConsumeToken();
ArgInfo.Type = 0;
if (Tok.is(tok::l_paren)) ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec);
ArgInfo.ArgAttrs = 0;
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
ArgInfo.ArgAttrs = ParseAttributes();
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); break;
}
ArgInfo.Name = Tok.getIdentifierInfo();
ArgInfo.NameLoc = Tok.getLocation();
ConsumeToken();
ArgInfos.push_back(ArgInfo);
KeyIdents.push_back(SelIdent);
SourceLocation Loc;
SelIdent = ParseObjCSelectorPiece(Loc);
if (!SelIdent && Tok.isNot(tok::colon))
break;
}
bool isVariadic = false;
while (Tok.is(tok::comma)) {
ConsumeToken();
if (Tok.is(tok::ellipsis)) {
isVariadic = true;
ConsumeToken();
break;
}
DeclSpec DS;
ParseDeclarationSpecifiers(DS);
Declarator ParmDecl(DS, Declarator::PrototypeContext);
ParseDeclarator(ParmDecl);
CargNames.push_back(ParmDecl);
}
AttributeList *MethodAttrs = 0;
if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
MethodAttrs = ParseAttributes();
Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
&KeyIdents[0]);
return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
mType, IDecl, DSRet, ReturnType, Sel,
&ArgInfos[0], CargNames, MethodAttrs,
MethodImplKind, isVariadic);
}
bool Parser::
ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols,
bool WarnOnDeclarations, SourceLocation &EndLoc) {
assert(Tok.is(tok::less) && "expected <");
ConsumeToken();
llvm::SmallVector<IdentifierLocPair, 8> ProtocolIdents;
while (1) {
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
SkipUntil(tok::greater);
return true;
}
ProtocolIdents.push_back(std::make_pair(Tok.getIdentifierInfo(),
Tok.getLocation()));
ConsumeToken();
if (Tok.isNot(tok::comma))
break;
ConsumeToken();
}
if (Tok.isNot(tok::greater)) {
Diag(Tok, diag::err_expected_greater);
return true;
}
EndLoc = ConsumeAnyToken();
Actions.FindProtocolDeclaration(WarnOnDeclarations,
&ProtocolIdents[0], ProtocolIdents.size(),
Protocols);
return false;
}
void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl,
SourceLocation atLoc) {
assert(Tok.is(tok::l_brace) && "expected {");
llvm::SmallVector<DeclPtrTy, 32> AllIvarDecls;
llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators;
ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope);
SourceLocation LBraceLoc = ConsumeBrace();
tok::ObjCKeywordKind visibility = tok::objc_protected;
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
if (Tok.is(tok::semi)) {
Diag(Tok, diag::ext_extra_struct_semi);
ConsumeToken();
continue;
}
if (Tok.is(tok::at)) { ConsumeToken(); switch (Tok.getObjCKeywordID()) {
case tok::objc_private:
case tok::objc_public:
case tok::objc_protected:
case tok::objc_package:
visibility = Tok.getObjCKeywordID();
ConsumeToken();
continue;
default:
Diag(Tok, diag::err_objc_illegal_visibility_spec);
continue;
}
}
DeclSpec DS;
FieldDeclarators.clear();
ParseStructDeclaration(DS, FieldDeclarators);
for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) {
FieldDeclarator &FD = FieldDeclarators[i];
DeclPtrTy Field = Actions.ActOnIvar(CurScope,
DS.getSourceRange().getBegin(),
FD.D, FD.BitfieldSize, visibility);
AllIvarDecls.push_back(Field);
}
if (Tok.is(tok::semi)) {
ConsumeToken();
} else {
Diag(Tok, diag::err_expected_semi_decl_list);
SkipUntil(tok::r_brace, true, true);
}
}
SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc);
Actions.ActOnFields(CurScope, atLoc, interfaceDecl,
&AllIvarDecls[0], AllIvarDecls.size(),
LBraceLoc, RBraceLoc, 0);
return;
}
Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
AttributeList *attrList) {
assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
"ParseObjCAtProtocolDeclaration(): Expected @protocol");
ConsumeToken();
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); return DeclPtrTy();
}
IdentifierInfo *protocolName = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken();
if (Tok.is(tok::semi)) { IdentifierLocPair ProtoInfo(protocolName, nameLoc);
ConsumeToken();
return Actions.ActOnForwardProtocolDeclaration(AtLoc, &ProtoInfo, 1,
attrList);
}
if (Tok.is(tok::comma)) { llvm::SmallVector<IdentifierLocPair, 8> ProtocolRefs;
ProtocolRefs.push_back(std::make_pair(protocolName, nameLoc));
while (1) {
ConsumeToken(); if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
SkipUntil(tok::semi);
return DeclPtrTy();
}
ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(),
Tok.getLocation()));
ConsumeToken();
if (Tok.isNot(tok::comma))
break;
}
if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
return DeclPtrTy();
return Actions.ActOnForwardProtocolDeclaration(AtLoc,
&ProtocolRefs[0],
ProtocolRefs.size(),
attrList);
}
SourceLocation EndProtoLoc;
llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, false, EndProtoLoc))
return DeclPtrTy();
DeclPtrTy ProtoType =
Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc,
&ProtocolRefs[0], ProtocolRefs.size(),
EndProtoLoc, attrList);
ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol);
return ProtoType;
}
Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration(
SourceLocation atLoc) {
assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
"ParseObjCAtImplementationDeclaration(): Expected @implementation");
ConsumeToken();
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); return DeclPtrTy();
}
IdentifierInfo *nameId = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken();
if (Tok.is(tok::l_paren)) {
SourceLocation lparenLoc = ConsumeParen();
SourceLocation categoryLoc, rparenLoc;
IdentifierInfo *categoryId = 0;
if (Tok.is(tok::identifier)) {
categoryId = Tok.getIdentifierInfo();
categoryLoc = ConsumeToken();
} else {
Diag(Tok, diag::err_expected_ident); return DeclPtrTy();
}
if (Tok.isNot(tok::r_paren)) {
Diag(Tok, diag::err_expected_rparen);
SkipUntil(tok::r_paren, false); return DeclPtrTy();
}
rparenLoc = ConsumeParen();
DeclPtrTy ImplCatType = Actions.ActOnStartCategoryImplementation(
atLoc, nameId, nameLoc, categoryId,
categoryLoc);
ObjCImpDecl = ImplCatType;
return DeclPtrTy();
}
SourceLocation superClassLoc;
IdentifierInfo *superClassId = 0;
if (Tok.is(tok::colon)) {
ConsumeToken();
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); return DeclPtrTy();
}
superClassId = Tok.getIdentifierInfo();
superClassLoc = ConsumeToken(); }
DeclPtrTy ImplClsType = Actions.ActOnStartClassImplementation(
atLoc, nameId, nameLoc,
superClassId, superClassLoc);
if (Tok.is(tok::l_brace)) ParseObjCClassInstanceVariables(ImplClsType, atLoc);
ObjCImpDecl = ImplClsType;
return DeclPtrTy();
}
Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) {
assert(Tok.isObjCAtKeyword(tok::objc_end) &&
"ParseObjCAtEndDeclaration(): Expected @end");
DeclPtrTy Result = ObjCImpDecl;
ConsumeToken(); if (ObjCImpDecl) {
Actions.ActOnAtEnd(atLoc, ObjCImpDecl);
ObjCImpDecl = DeclPtrTy();
}
else
Diag(atLoc, diag::warn_expected_implementation); return Result;
}
Parser::DeclPtrTy Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
"ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
ConsumeToken(); if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
return DeclPtrTy();
}
IdentifierInfo *aliasId = Tok.getIdentifierInfo();
SourceLocation aliasLoc = ConsumeToken(); if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
return DeclPtrTy();
}
IdentifierInfo *classId = Tok.getIdentifierInfo();
SourceLocation classLoc = ConsumeToken(); if (Tok.isNot(tok::semi)) {
Diag(Tok, diag::err_expected_semi_after) << "@compatibility_alias";
return DeclPtrTy();
}
return Actions.ActOnCompatiblityAlias(atLoc, aliasId, aliasLoc,
classId, classLoc);
}
Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
assert(Tok.isObjCAtKeyword(tok::objc_synthesize) &&
"ParseObjCPropertyDynamic(): Expected '@synthesize'");
SourceLocation loc = ConsumeToken(); if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
return DeclPtrTy();
}
while (Tok.is(tok::identifier)) {
IdentifierInfo *propertyIvar = 0;
IdentifierInfo *propertyId = Tok.getIdentifierInfo();
SourceLocation propertyLoc = ConsumeToken(); if (Tok.is(tok::equal)) {
ConsumeToken(); if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
break;
}
propertyIvar = Tok.getIdentifierInfo();
ConsumeToken(); }
Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, true, ObjCImpDecl,
propertyId, propertyIvar);
if (Tok.isNot(tok::comma))
break;
ConsumeToken(); }
if (Tok.isNot(tok::semi))
Diag(Tok, diag::err_expected_semi_after) << "@synthesize";
return DeclPtrTy();
}
Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
assert(Tok.isObjCAtKeyword(tok::objc_dynamic) &&
"ParseObjCPropertyDynamic(): Expected '@dynamic'");
SourceLocation loc = ConsumeToken(); if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
return DeclPtrTy();
}
while (Tok.is(tok::identifier)) {
IdentifierInfo *propertyId = Tok.getIdentifierInfo();
SourceLocation propertyLoc = ConsumeToken(); Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, false, ObjCImpDecl,
propertyId, 0);
if (Tok.isNot(tok::comma))
break;
ConsumeToken(); }
if (Tok.isNot(tok::semi))
Diag(Tok, diag::err_expected_semi_after) << "@dynamic";
return DeclPtrTy();
}
Parser::OwningStmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
OwningExprResult Res(Actions);
ConsumeToken(); if (Tok.isNot(tok::semi)) {
Res = ParseExpression();
if (Res.isInvalid()) {
SkipUntil(tok::semi);
return StmtError();
}
}
ConsumeToken(); return Actions.ActOnObjCAtThrowStmt(atLoc, move(Res), CurScope);
}
Parser::OwningStmtResult
Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
ConsumeToken(); if (Tok.isNot(tok::l_paren)) {
Diag(Tok, diag::err_expected_lparen_after) << "@synchronized";
return StmtError();
}
ConsumeParen(); OwningExprResult Res(ParseExpression());
if (Res.isInvalid()) {
SkipUntil(tok::semi);
return StmtError();
}
if (Tok.isNot(tok::r_paren)) {
Diag(Tok, diag::err_expected_lbrace);
return StmtError();
}
ConsumeParen(); if (Tok.isNot(tok::l_brace)) {
Diag(Tok, diag::err_expected_lbrace);
return StmtError();
}
ParseScope BodyScope(this, Scope::DeclScope);
OwningStmtResult SynchBody(ParseCompoundStatementBody());
BodyScope.Exit();
if (SynchBody.isInvalid())
SynchBody = Actions.ActOnNullStmt(Tok.getLocation());
return Actions.ActOnObjCAtSynchronizedStmt(atLoc, move(Res), move(SynchBody));
}
Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
bool catch_or_finally_seen = false;
ConsumeToken(); if (Tok.isNot(tok::l_brace)) {
Diag(Tok, diag::err_expected_lbrace);
return StmtError();
}
OwningStmtResult CatchStmts(Actions);
OwningStmtResult FinallyStmt(Actions);
ParseScope TryScope(this, Scope::DeclScope);
OwningStmtResult TryBody(ParseCompoundStatementBody());
TryScope.Exit();
if (TryBody.isInvalid())
TryBody = Actions.ActOnNullStmt(Tok.getLocation());
while (Tok.is(tok::at)) {
Token AfterAt = GetLookAheadToken(1);
if (!AfterAt.isObjCAtKeyword(tok::objc_catch) &&
!AfterAt.isObjCAtKeyword(tok::objc_finally))
break;
SourceLocation AtCatchFinallyLoc = ConsumeToken();
if (Tok.isObjCAtKeyword(tok::objc_catch)) {
DeclPtrTy FirstPart;
ConsumeToken(); if (Tok.is(tok::l_paren)) {
ConsumeParen();
ParseScope CatchScope(this, Scope::DeclScope|Scope::AtCatchScope);
if (Tok.isNot(tok::ellipsis)) {
DeclSpec DS;
ParseDeclarationSpecifiers(DS);
Declarator ParmDecl(DS, Declarator::PrototypeContext);
ParseDeclarator(ParmDecl);
FirstPart = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
} else
ConsumeToken();
SourceLocation RParenLoc;
if (Tok.is(tok::r_paren))
RParenLoc = ConsumeParen();
else SkipUntil(tok::r_paren, true, false);
OwningStmtResult CatchBody(Actions, true);
if (Tok.is(tok::l_brace))
CatchBody = ParseCompoundStatementBody();
else
Diag(Tok, diag::err_expected_lbrace);
if (CatchBody.isInvalid())
CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
CatchStmts = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
RParenLoc, FirstPart, move(CatchBody),
move(CatchStmts));
} else {
Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
<< "@catch clause";
return StmtError();
}
catch_or_finally_seen = true;
} else {
assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?");
ConsumeToken(); ParseScope FinallyScope(this, Scope::DeclScope);
OwningStmtResult FinallyBody(Actions, true);
if (Tok.is(tok::l_brace))
FinallyBody = ParseCompoundStatementBody();
else
Diag(Tok, diag::err_expected_lbrace);
if (FinallyBody.isInvalid())
FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());
FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc,
move(FinallyBody));
catch_or_finally_seen = true;
break;
}
}
if (!catch_or_finally_seen) {
Diag(atLoc, diag::err_missing_catch_finally);
return StmtError();
}
return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody), move(CatchStmts),
move(FinallyStmt));
}
Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() {
DeclPtrTy MDecl = ParseObjCMethodPrototype(ObjCImpDecl);
PrettyStackTraceActionsDecl CrashInfo(MDecl, Tok.getLocation(), Actions,
PP.getSourceManager(),
"parsing Objective-C method");
if (Tok.is(tok::semi))
ConsumeToken();
if (Tok.isNot(tok::l_brace)) {
Diag(Tok, diag::err_expected_method_body);
SkipUntil(tok::l_brace, true, true);
if (Tok.isNot(tok::l_brace))
return DeclPtrTy();
}
SourceLocation BraceLoc = Tok.getLocation();
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
Actions.ActOnStartOfObjCMethodDef(CurScope, MDecl);
OwningStmtResult FnBody(ParseCompoundStatementBody());
if (FnBody.isInvalid())
FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc,
MultiStmtArg(Actions), false);
Actions.ActOnFinishFunctionBody(MDecl, move(FnBody));
BodyScope.Exit();
return MDecl;
}
Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
if (Tok.isObjCAtKeyword(tok::objc_try)) {
return ParseObjCTryStmt(AtLoc);
} else if (Tok.isObjCAtKeyword(tok::objc_throw))
return ParseObjCThrowStmt(AtLoc);
else if (Tok.isObjCAtKeyword(tok::objc_synchronized))
return ParseObjCSynchronizedStmt(AtLoc);
OwningExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
if (Res.isInvalid()) {
SkipUntil(tok::semi);
return StmtError();
}
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
return Actions.ActOnExprStmt(move(Res));
}
Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
switch (Tok.getKind()) {
case tok::string_literal: case tok::wide_string_literal:
return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc));
default:
if (Tok.getIdentifierInfo() == 0)
return ExprError(Diag(AtLoc, diag::err_unexpected_at));
switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
case tok::objc_encode:
return ParsePostfixExpressionSuffix(ParseObjCEncodeExpression(AtLoc));
case tok::objc_protocol:
return ParsePostfixExpressionSuffix(ParseObjCProtocolExpression(AtLoc));
case tok::objc_selector:
return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc));
default:
return ExprError(Diag(AtLoc, diag::err_unexpected_at));
}
}
}
Parser::OwningExprResult Parser::ParseObjCMessageExpression() {
assert(Tok.is(tok::l_square) && "'[' expected");
SourceLocation LBracLoc = ConsumeBracket();
if (isTokObjCMessageIdentifierReceiver()) {
IdentifierInfo *ReceiverName = Tok.getIdentifierInfo();
if (ReceiverName != Ident_super || GetLookAheadToken(1).isNot(tok::period)) {
SourceLocation NameLoc = ConsumeToken();
return ParseObjCMessageExpressionBody(LBracLoc, NameLoc, ReceiverName,
ExprArg(Actions));
}
}
OwningExprResult Res(ParseExpression());
if (Res.isInvalid()) {
SkipUntil(tok::r_square);
return move(Res);
}
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
0, move(Res));
}
Parser::OwningExprResult
Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
SourceLocation NameLoc,
IdentifierInfo *ReceiverName,
ExprArg ReceiverExpr) {
SourceLocation Loc;
IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);
SourceLocation SelectorLoc = Loc;
llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
ExprVector KeyExprs(Actions);
if (Tok.is(tok::colon)) {
while (1) {
KeyIdents.push_back(selIdent);
if (Tok.isNot(tok::colon)) {
Diag(Tok, diag::err_expected_colon);
SkipUntil(tok::r_square);
return ExprError();
}
ConsumeToken(); OwningExprResult Res(ParseAssignmentExpression());
if (Res.isInvalid()) {
SkipUntil(tok::r_square);
return move(Res);
}
KeyExprs.push_back(Res.release());
selIdent = ParseObjCSelectorPiece(Loc);
if (!selIdent && Tok.isNot(tok::colon))
break;
}
while (Tok.is(tok::comma)) {
ConsumeToken(); OwningExprResult Res(ParseAssignmentExpression());
if (Res.isInvalid()) {
SkipUntil(tok::r_square);
return move(Res);
}
KeyExprs.push_back(Res.release());
}
} else if (!selIdent) {
Diag(Tok, diag::err_expected_ident);
SkipUntil(tok::r_square);
return ExprError();
}
if (Tok.isNot(tok::r_square)) {
Diag(Tok, diag::err_expected_rsquare);
SkipUntil(tok::r_square);
return ExprError();
}
SourceLocation RBracLoc = ConsumeBracket();
unsigned nKeys = KeyIdents.size();
if (nKeys == 0)
KeyIdents.push_back(selIdent);
Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]);
if (ReceiverName)
return Owned(Actions.ActOnClassMessage(CurScope, ReceiverName, Sel,
LBracLoc, NameLoc, SelectorLoc,
RBracLoc,
KeyExprs.take(), KeyExprs.size()));
return Owned(Actions.ActOnInstanceMessage(ReceiverExpr.release(), Sel,
LBracLoc, SelectorLoc, RBracLoc,
KeyExprs.take(), KeyExprs.size()));
}
Parser::OwningExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
OwningExprResult Res(ParseStringLiteralExpression());
if (Res.isInvalid()) return move(Res);
llvm::SmallVector<SourceLocation, 4> AtLocs;
ExprVector AtStrings(Actions);
AtLocs.push_back(AtLoc);
AtStrings.push_back(Res.release());
while (Tok.is(tok::at)) {
AtLocs.push_back(ConsumeToken());
if (!isTokenStringLiteral())
return ExprError(Diag(Tok, diag::err_objc_concat_string));
OwningExprResult Lit(ParseStringLiteralExpression());
if (Lit.isInvalid())
return move(Lit);
AtStrings.push_back(Lit.release());
}
return Owned(Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.take(),
AtStrings.size()));
}
Parser::OwningExprResult
Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!");
SourceLocation EncLoc = ConsumeToken();
if (Tok.isNot(tok::l_paren))
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@encode");
SourceLocation LParenLoc = ConsumeParen();
TypeResult Ty = ParseTypeName();
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
if (Ty.isInvalid())
return ExprError();
return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, LParenLoc,
Ty.get(), RParenLoc));
}
Parser::OwningExprResult
Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
SourceLocation ProtoLoc = ConsumeToken();
if (Tok.isNot(tok::l_paren))
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@protocol");
SourceLocation LParenLoc = ConsumeParen();
if (Tok.isNot(tok::identifier))
return ExprError(Diag(Tok, diag::err_expected_ident));
IdentifierInfo *protocolId = Tok.getIdentifierInfo();
ConsumeToken();
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
return Owned(Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
LParenLoc, RParenLoc));
}
Parser::OwningExprResult
Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
SourceLocation SelectorLoc = ConsumeToken();
if (Tok.isNot(tok::l_paren))
return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector");
llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
SourceLocation LParenLoc = ConsumeParen();
SourceLocation sLoc;
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc);
if (!SelIdent && Tok.isNot(tok::colon)) return ExprError(Diag(Tok, diag::err_expected_ident));
KeyIdents.push_back(SelIdent);
unsigned nColons = 0;
if (Tok.isNot(tok::r_paren)) {
while (1) {
if (Tok.isNot(tok::colon))
return ExprError(Diag(Tok, diag::err_expected_colon));
nColons++;
ConsumeToken(); if (Tok.is(tok::r_paren))
break;
SourceLocation Loc;
SelIdent = ParseObjCSelectorPiece(Loc);
KeyIdents.push_back(SelIdent);
if (!SelIdent && Tok.isNot(tok::colon))
break;
}
}
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
return Owned(Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
LParenLoc, RParenLoc));
}