#include "clang/Parse/Parser.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "RAIIObjectsForParser.h"
#include "clang/Sema/Designator.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
bool Parser::MayBeDesignationStart() {
switch (Tok.getKind()) {
default:
return false;
case tok::period: return true;
case tok::l_square: { if (!PP.getLangOpts().CPlusPlus0x)
return true;
switch (PP.LookAhead(0).getKind()) {
case tok::equal:
case tok::r_square:
return false;
case tok::amp:
case tok::kw_this:
case tok::identifier:
break;
default:
return true;
}
break;
}
case tok::identifier: return PP.LookAhead(0).is(tok::colon);
}
TentativeParsingAction Tentative(*this);
ConsumeBracket();
while (true) {
switch (Tok.getKind()) {
case tok::equal:
case tok::amp:
case tok::identifier:
case tok::kw_this:
ConsumeToken();
continue;
case tok::comma:
Tentative.Revert();
return false;
case tok::r_square: {
ConsumeBracket();
tok::TokenKind Kind = Tok.getKind();
Tentative.Revert();
return Kind == tok::equal;
}
default:
Tentative.Revert();
return true;
}
}
return true;
}
static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
Designation &Desig) {
if (Desig.getNumDesignators() == 1 &&
(Desig.getDesignator(0).isArrayDesignator() ||
Desig.getDesignator(0).isArrayRangeDesignator()))
P.Diag(Loc, diag::ext_gnu_missing_equal_designator);
else if (Desig.getNumDesignators() > 0)
P.Diag(Loc, diag::err_expected_equal_designator);
}
ExprResult Parser::ParseInitializerWithPotentialDesignator() {
if (Tok.is(tok::identifier)) {
const IdentifierInfo *FieldName = Tok.getIdentifierInfo();
SmallString<256> NewSyntax;
llvm::raw_svector_ostream(NewSyntax) << '.' << FieldName->getName()
<< " = ";
SourceLocation NameLoc = ConsumeToken();
assert(Tok.is(tok::colon) && "MayBeDesignationStart not working properly!");
SourceLocation ColonLoc = ConsumeToken();
Diag(NameLoc, diag::ext_gnu_old_style_field_designator)
<< FixItHint::CreateReplacement(SourceRange(NameLoc, ColonLoc),
NewSyntax.str());
Designation D;
D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc));
return Actions.ActOnDesignatedInitializer(D, ColonLoc, true,
ParseInitializer());
}
Designation Desig;
while (Tok.is(tok::period) || Tok.is(tok::l_square)) {
if (Tok.is(tok::period)) {
SourceLocation DotLoc = ConsumeToken();
if (Tok.isNot(tok::identifier)) {
Diag(Tok.getLocation(), diag::err_expected_field_designator);
return ExprError();
}
Desig.AddDesignator(Designator::getField(Tok.getIdentifierInfo(), DotLoc,
Tok.getLocation()));
ConsumeToken(); continue;
}
assert(Tok.is(tok::l_square) && "Unexpected token!");
InMessageExpressionRAIIObject InMessage(*this, true);
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
SourceLocation StartLoc = T.getOpenLocation();
ExprResult Idx;
if (getLangOpts().ObjC1 && getLangOpts().CPlusPlus) {
if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
NextToken().isNot(tok::period) &&
getCurScope()->isInObjcMethodScope()) {
CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
ConsumeToken(),
ParsedType(),
0);
}
bool IsExpr;
void *TypeOrExpr;
if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
SkipUntil(tok::r_square);
return ExprError();
}
if (!IsExpr) {
CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
SourceLocation(),
ParsedType::getFromOpaquePtr(TypeOrExpr),
0);
}
Idx = ExprResult(static_cast<Expr*>(TypeOrExpr));
} else if (getLangOpts().ObjC1 && Tok.is(tok::identifier)) {
IdentifierInfo *II = Tok.getIdentifierInfo();
SourceLocation IILoc = Tok.getLocation();
ParsedType ReceiverType;
switch (Sema::ObjCMessageKind Kind
= Actions.getObjCMessageKind(getCurScope(), II, IILoc,
II == Ident_super,
NextToken().is(tok::period),
ReceiverType)) {
case Sema::ObjCSuperMessage:
case Sema::ObjCClassMessage:
CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
if (Kind == Sema::ObjCSuperMessage)
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
ConsumeToken(),
ParsedType(),
0);
ConsumeToken(); if (!ReceiverType) {
SkipUntil(tok::r_square);
return ExprError();
}
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
SourceLocation(),
ReceiverType,
0);
case Sema::ObjCInstanceMessage:
break;
}
}
if (!Idx.get()) {
Idx = ParseAssignmentExpression();
if (Idx.isInvalid()) {
SkipUntil(tok::r_square);
return Idx;
}
}
if (getLangOpts().ObjC1 && Tok.isNot(tok::ellipsis) &&
Tok.isNot(tok::r_square)) {
CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig);
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
SourceLocation(),
ParsedType(),
Idx.take());
}
if (Tok.isNot(tok::ellipsis)) {
Desig.AddDesignator(Designator::getArray(Idx.release(), StartLoc));
} else {
Diag(Tok, diag::ext_gnu_array_range);
SourceLocation EllipsisLoc = ConsumeToken();
ExprResult RHS(ParseConstantExpression());
if (RHS.isInvalid()) {
SkipUntil(tok::r_square);
return RHS;
}
Desig.AddDesignator(Designator::getArrayRange(Idx.release(),
RHS.release(),
StartLoc, EllipsisLoc));
}
T.consumeClose();
Desig.getDesignator(Desig.getNumDesignators() - 1).setRBracketLoc(
T.getCloseLocation());
}
assert(!Desig.empty() && "Designator is empty?");
if (Tok.is(tok::equal)) {
SourceLocation EqualLoc = ConsumeToken();
return Actions.ActOnDesignatedInitializer(Desig, EqualLoc, false,
ParseInitializer());
}
if (Desig.getNumDesignators() == 1 &&
(Desig.getDesignator(0).isArrayDesignator() ||
Desig.getDesignator(0).isArrayRangeDesignator())) {
Diag(Tok, diag::ext_gnu_missing_equal_designator)
<< FixItHint::CreateInsertion(Tok.getLocation(), "= ");
return Actions.ActOnDesignatedInitializer(Desig, Tok.getLocation(),
true, ParseInitializer());
}
Diag(Tok, diag::err_expected_equal_designator);
return ExprError();
}
ExprResult Parser::ParseBraceInitializer() {
InMessageExpressionRAIIObject InMessage(*this, false);
BalancedDelimiterTracker T(*this, tok::l_brace);
T.consumeOpen();
SourceLocation LBraceLoc = T.getOpenLocation();
ExprVector InitExprs;
if (Tok.is(tok::r_brace)) {
if (!getLangOpts().CPlusPlus)
Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
return Actions.ActOnInitList(LBraceLoc, MultiExprArg(), ConsumeBrace());
}
bool InitExprsOk = true;
while (1) {
if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||
Tok.is(tok::kw___if_not_exists))) {
if (ParseMicrosoftIfExistsBraceInitializer(InitExprs, InitExprsOk)) {
if (Tok.isNot(tok::comma)) break;
ConsumeToken();
}
if (Tok.is(tok::r_brace)) break;
continue;
}
ExprResult SubElt;
if (MayBeDesignationStart())
SubElt = ParseInitializerWithPotentialDesignator();
else
SubElt = ParseInitializer();
if (Tok.is(tok::ellipsis))
SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken());
if (!SubElt.isInvalid()) {
InitExprs.push_back(SubElt.release());
} else {
InitExprsOk = false;
if (Tok.isNot(tok::comma)) {
SkipUntil(tok::r_brace, false, true);
break;
}
}
if (Tok.isNot(tok::comma)) break;
ConsumeToken();
if (Tok.is(tok::r_brace)) break;
}
bool closed = !T.consumeClose();
if (InitExprsOk && closed)
return Actions.ActOnInitList(LBraceLoc, InitExprs,
T.getCloseLocation());
return ExprError(); }
bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
bool &InitExprsOk) {
bool trailingComma = false;
IfExistsCondition Result;
if (ParseMicrosoftIfExistsCondition(Result))
return false;
BalancedDelimiterTracker Braces(*this, tok::l_brace);
if (Braces.consumeOpen()) {
Diag(Tok, diag::err_expected_lbrace);
return false;
}
switch (Result.Behavior) {
case IEB_Parse:
break;
case IEB_Dependent:
Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists)
<< Result.IsIfExists;
case IEB_Skip:
Braces.skipToEnd();
return false;
}
while (Tok.isNot(tok::eof)) {
trailingComma = false;
ExprResult SubElt;
if (MayBeDesignationStart())
SubElt = ParseInitializerWithPotentialDesignator();
else
SubElt = ParseInitializer();
if (Tok.is(tok::ellipsis))
SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken());
if (!SubElt.isInvalid())
InitExprs.push_back(SubElt.release());
else
InitExprsOk = false;
if (Tok.is(tok::comma)) {
ConsumeToken();
trailingComma = true;
}
if (Tok.is(tok::r_brace))
break;
}
Braces.consumeClose();
return !trailingComma;
}