Files
swift-mirror/lib/Parse/Parser.cpp
Chris Lattner 3b4a8b03d2 1. With overloading in play, SemaDecl should never resolve unqualified lookup that hits at translation unit scope to a DeclRefExpr. Doing so can break overloading.
2. This exposed a bug: when parsing structs, we weren't adding all decls to the translation unit, we were just adding the type alias.
3. This exposed that TypeChecking wasn't handling OneOfElementDecl.
4. Introduce a new NLKind enum in NameLookup instead of passing around a bool.
5. Have unqualified lookup that returns an overload set form a new OverloadSetRefExpr, which has dependent type.
6. Enhance various stuff to handle OverloadSetRefExpr.  It's still not fully handled yet though, so it can't be used for anything useful.
7. Change Expr.cpp to print types with << instead of T->print(OS) which is simpler and correct in the face of null.

Swift SVN r351
2011-04-10 05:57:10 +00:00

1151 lines
33 KiB
C++

//===--- Parser.cpp - Swift Language Parser -------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements the Swift parser.
//
//===----------------------------------------------------------------------===//
#include "swift/Parse/Parser.h"
#include "swift/Parse/Lexer.h"
#include "swift/Sema/Sema.h"
#include "swift/Sema/Scope.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Types.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/ADT/NullablePtr.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Twine.h"
using namespace swift;
using llvm::SMLoc;
using llvm::NullablePtr;
//===----------------------------------------------------------------------===//
// Setup and Helper Methods
//===----------------------------------------------------------------------===//
Parser::Parser(unsigned BufferID, ASTContext &Context)
: SourceMgr(Context.SourceMgr),
L(*new Lexer(BufferID, Context)),
S(*new Sema(Context)) {
}
Parser::~Parser() {
delete &L;
delete &S;
}
void Parser::note(SMLoc Loc, const llvm::Twine &Message) {
SourceMgr.PrintMessage(Loc, Message, "note");
}
void Parser::warning(SMLoc Loc, const llvm::Twine &Message) {
SourceMgr.PrintMessage(Loc, Message, "warning");
}
void Parser::error(SMLoc Loc, const llvm::Twine &Message) {
S.Context.setHadError();
SourceMgr.PrintMessage(Loc, Message, "error");
}
void Parser::consumeToken() {
assert(Tok.isNot(tok::eof) && "Lexing past eof!");
L.Lex(Tok);
}
/// skipUntil - Read tokens until we get to the specified token, then return.
/// Because we cannot guarantee that the token will ever occur, this skips to
/// some likely good stopping point.
///
void Parser::skipUntil(tok::TokenKind T) {
// tok::unknown is a sentinel that means "don't skip".
if (T == tok::unknown) return;
while (Tok.isNot(tok::eof) && Tok.isNot(T)) {
switch (Tok.getKind()) {
default: consumeToken(); break;
// TODO: Handle paren/brace/bracket recovery.
}
}
}
//===----------------------------------------------------------------------===//
// Primitive Parsing
//===----------------------------------------------------------------------===//
/// parseIdentifier - Consume an identifier if present and return its name in
/// Result. Otherwise, emit an error and return true.
bool Parser::parseIdentifier(Identifier &Result, const llvm::Twine &Message) {
if (Tok.is(tok::identifier)) {
Result = S.Context.getIdentifier(Tok.getText());
consumeToken(tok::identifier);
return false;
}
error(Tok.getLoc(), Message);
return true;
}
/// parseToken - The parser expects that 'K' is next in the input. If so, it is
/// consumed and false is returned.
///
/// If the input is malformed, this emits the specified error diagnostic.
/// Next, if SkipToTok is specified, it calls skipUntil(SkipToTok). Finally,
/// true is returned.
bool Parser::parseToken(tok::TokenKind K, const char *Message,
tok::TokenKind SkipToTok) {
if (Tok.is(K)) {
consumeToken(K);
return false;
}
error(Tok.getLoc(), Message);
skipUntil(SkipToTok);
// If we skipped ahead to the missing token and found it, consume it as if
// there were no error.
if (K == SkipToTok && Tok.is(SkipToTok))
consumeToken();
return true;
}
/// value-specifier:
/// ':' type
/// ':' type '=' expr
/// '=' expr
bool Parser::parseValueSpecifier(Type &Ty, NullablePtr<Expr> &Init) {
// Diagnose when we don't have a type or an expression.
if (Tok.isNot(tok::colon) && Tok.isNot(tok::equal)) {
error(Tok.getLoc(), "expected a type or an initializer");
// TODO: Recover better by still creating var, but making it have
// 'invalid' type so that uses of the identifier are not errors.
return true;
}
// Parse the type if present.
if (consumeIf(tok::colon) &&
parseType(Ty, "expected type in var declaration"))
return true;
// Parse the initializer, if present.
if (consumeIf(tok::equal)) {
if (parseExpr(Init, "expected expression in var declaration"))
return true;
// If there was an expression, but it had a parse error, give the var decl
// an artificial int type to avoid chained errors.
// FIXME: We really need to distinguish erroneous expr from missing expr in
// ActOnVarDecl.
if (Init.isNull() && Ty.isNull())
Ty = S.Context.TheInt32Type;
}
return false;
}
//===----------------------------------------------------------------------===//
// Decl Parsing
//===----------------------------------------------------------------------===//
/// ParseTranslationUnit
/// translation-unit:
/// top-level-item*
TranslationUnitDecl *Parser::parseTranslationUnit() {
// Prime the lexer.
consumeToken();
SMLoc FileStartLoc = Tok.getLoc();
TranslationUnitDecl *Result = new (S.Context) TranslationUnitDecl(S.Context);
// Parse the body of the file.
llvm::SmallVector<ExprOrDecl, 128> Items;
bool MissingSemiAtEnd = false; // Don't care, FIXME remove.
parseDeclExprList(Items, MissingSemiAtEnd, true);
// Notify sema about the end of the translation unit.
S.decl.handleEndOfTranslationUnit(Result, FileStartLoc, Items, Tok.getLoc());
return Result;
}
/// parseAttribute
/// attribute:
/// 'infix' '=' numeric_constant
bool Parser::parseAttribute(DeclAttributes &Attributes) {
if (Tok.is(tok::identifier) && Tok.getText() == "infix") {
if (Attributes.InfixPrecedence != -1)
error(Tok.getLoc(), "infix precedence repeatedly specified");
consumeToken(tok::identifier);
// The default infix precedence is 100.
Attributes.InfixPrecedence = 100;
if (consumeIf(tok::equal)) {
SMLoc PrecLoc = Tok.getLoc();
llvm::StringRef Text = Tok.getText();
if (!parseToken(tok::numeric_constant,
"expected precedence number in 'infix' attribute")) {
long long Value;
if (Text.getAsInteger(10, Value) || Value > 255 || Value < 0)
error(PrecLoc, "invalid precedence: value must be between 0 and 255");
else
Attributes.InfixPrecedence = Value;
}
}
return false;
}
error(Tok.getLoc(), "unknown declaration attribute");
skipUntil(tok::r_square);
return true;
}
/// parseAttributeList
/// attribute-list:
/// '[' ']'
/// '[' attribute (',' attribute)* ']'
void Parser::parseAttributeList(DeclAttributes &Attributes) {
Attributes.LSquareLoc = Tok.getLoc();
consumeToken(tok::l_square);
// If this is an empty attribute list, consume it and return.
if (Tok.is(tok::r_square)) {
Attributes.RSquareLoc = Tok.getLoc();
consumeToken(tok::r_square);
return;
}
bool HadError = parseAttribute(Attributes);
while (Tok.is(tok::comma)) {
consumeToken(tok::comma);
HadError |= parseAttribute(Attributes);
}
Attributes.RSquareLoc = Tok.getLoc();
if (consumeIf(tok::r_square))
return;
// Otherwise, there was an error parsing the attribute list. If we already
// reported an error, skip to a ], otherwise report the error.
if (!HadError)
parseToken(tok::r_square, "expected ']' or ',' in attribute list",
tok::r_square);
else {
skipUntil(tok::r_square);
consumeIf(tok::r_square);
}
}
/// parseDeclImport - Parse an 'import' declaration, returning null (and doing
/// no token skipping) on error.
///
/// decl-import:
/// 'import' attribute-list? identifier ('.' identifier)*
///
Decl *Parser::parseDeclImport() {
SMLoc ImportLoc = Tok.getLoc();
consumeToken(tok::kw_import);
DeclAttributes Attributes;
if (Tok.is(tok::l_square))
parseAttributeList(Attributes);
llvm::SmallVector<std::pair<Identifier, SMLoc>, 8> ImportPath(1);
ImportPath.back().second = Tok.getLoc();
if (parseIdentifier(ImportPath.back().first,
"expected module name in import declaration"))
return 0;
while (consumeIf(tok::period)) {
ImportPath.push_back(std::make_pair(Identifier(), Tok.getLoc()));
if (parseIdentifier(ImportPath.back().first,
"expected name in import declaration"))
return 0;
}
return S.decl.ActOnImportDecl(ImportLoc, ImportPath, Attributes);
}
/// parseVarName
/// var-name:
/// identifier
/// '(' ')'
/// '(' name (',' name)* ')'
bool Parser::parseVarName(DeclVarName &Name) {
// Single name case.
if (Tok.is(tok::identifier)) {
Name.LPLoc = Name.RPLoc = Tok.getLoc();
parseIdentifier(Name.Name, "");
return false;
}
Name.LPLoc = Tok.getLoc();
if (parseToken(tok::l_paren, "expected identifier or '(' in var name"))
return true;
llvm::SmallVector<DeclVarName*, 8> ChildNames;
if (Tok.isNot(tok::r_paren)) {
do {
DeclVarName *Elt = new (S.Context) DeclVarName();
if (parseVarName(*Elt)) return true;
ChildNames.push_back(Elt);
} while (consumeIf(tok::comma));
}
Name.RPLoc = Tok.getLoc();
if (parseToken(tok::r_paren, "expected ')' at end of var name"))
note(Name.LPLoc, "to match this '('");
Name.Elements = ChildNames;
Name.Elements = S.Context.AllocateCopy(Name.Elements);
return false;
}
/// parseDeclTypeAlias
/// decl-typealias:
/// 'typealias' identifier ':' type
TypeAliasDecl *Parser::parseDeclTypeAlias() {
SMLoc TypeAliasLoc = Tok.getLoc();
consumeToken(tok::kw_typealias);
Identifier Id;
Type Ty;
if (parseIdentifier(Id, "expected identifier in var declaration") ||
parseToken(tok::colon, "expected ':' in typealias declaration") ||
parseType(Ty, "expected type in var declaration"))
return 0;
return S.decl.ActOnTypeAlias(TypeAliasLoc, Id, Ty);
}
/// AddElementNamesForVarDecl - This recursive function walks a name specifier
/// adding ElementRefDecls for the named subcomponents and checking that types
/// match up correctly.
static void AddElementNamesForVarDecl(const DeclVarName *Name,
llvm::SmallVectorImpl<unsigned> &AccessPath,
VarDecl *VD, SemaDecl &SD,
llvm::SmallVectorImpl<Parser::ExprOrDecl> &Decls){
if (Name->isSimple()) {
// If this is a leaf name, ask sema to create a ElementRefDecl for us with
// the specified access path.
ElementRefDecl *ERD =
SD.ActOnElementName(Name->Name, Name->LPLoc, VD, AccessPath);
Decls.push_back(ERD);
SD.AddToScope(ERD);
return;
}
AccessPath.push_back(0);
for (unsigned i = 0, e = Name->Elements.size(); i != e; ++i) {
AccessPath.back() = i;
AddElementNamesForVarDecl(Name->Elements[i], AccessPath, VD, SD, Decls);
}
AccessPath.pop_back();
}
/// parseDeclVar - Parse a 'var' declaration, returning null (and doing no
/// token skipping) on error.
///
/// decl-var:
/// 'var' attribute-list? var-name value-specifier
bool Parser::parseDeclVar(llvm::SmallVectorImpl<ExprOrDecl> &Decls) {
SMLoc VarLoc = Tok.getLoc();
consumeToken(tok::kw_var);
DeclAttributes Attributes;
if (Tok.is(tok::l_square))
parseAttributeList(Attributes);
DeclVarName VarName;
if (parseVarName(VarName)) return true;
Type Ty;
NullablePtr<Expr> Init;
if (parseValueSpecifier(Ty, Init))
return true;
VarDecl *VD = S.decl.ActOnVarDecl(VarLoc, VarName, Ty, Init.getPtrOrNull(),
Attributes);
if (VD == 0) return true;
Decls.push_back(VD);
// Enter the declaration into the current scope. Since var's are not allowed
// to be recursive, they are entered after its initializer is parsed. This
// does mean that stuff like this is different than C:
// var x = 1; { var x = x+1; assert(x == 2); }
if (VarName.isSimple())
S.decl.AddToScope(VD);
else {
// If there is a more interesting name presented here, then we need to walk
// through it and synthesize the decls that reference the var elements as
// appropriate.
llvm::SmallVector<unsigned, 8> AccessPath;
AddElementNamesForVarDecl(VD->NestedName, AccessPath, VD, S.decl, Decls);
}
return false;
}
/// parseDeclFunc - Parse a 'func' declaration, returning null on error. The
/// caller handles this case and does recovery as appropriate.
///
/// decl-func:
/// 'func' attribute-list? identifier arg-list-type '=' expr
/// 'func' attribute-list? identifier arg-list-type expr-brace
/// 'func' attribute-list? identifier arg-list-type
FuncDecl *Parser::parseDeclFunc() {
SMLoc FuncLoc = Tok.getLoc();
consumeToken(tok::kw_func);
DeclAttributes Attributes;
// FIXME: Implicitly add immutable attribute.
if (Tok.is(tok::l_square))
parseAttributeList(Attributes);
Identifier Name;
if (parseIdentifier(Name, "expected identifier in func declaration"))
return 0;
// We force first type of a func declaration to be a tuple for consistency.
if (Tok.isNot(tok::l_paren)) {
error(Tok.getLoc(), "expected '(' in argument list of func declaration");
return 0;
}
Type FuncTy;
if (parseType(FuncTy))
return 0;
// If the parsed function type is not spelled as a function type (i.e., has an
// '->' in it), then it is implicitly a function that returns ().
if (!llvm::isa<FunctionType>(FuncTy.getPointer()))
FuncTy = S.type.ActOnFunctionType(FuncTy, SMLoc(),
S.Context.TheEmptyTupleType);
// Build the decl for the function.
FuncDecl *FD = S.decl.ActOnFuncDecl(FuncLoc, Name, FuncTy, Attributes);
// Enter the func into the current scope, which allows it to be visible and
// used within its body.
if (FD)
S.decl.AddToScope(FD);
// Enter the arguments for the function into a new function-body scope. We
// need this even if there is no function body to detect argument name
// duplication.
Scope FnBodyScope(S.decl);
if (FD)
S.decl.CreateArgumentDeclsForFunc(FD);
// Then parse the expression.
llvm::NullablePtr<Expr> Body;
// Check to see if we have a "= expr" or "{" which is a brace expr.
if (consumeIf(tok::equal)) {
if (parseExpr(Body, "expected expression parsing func body") ||
Body.isNull())
return 0; // FIXME: Need to call a new ActOnFuncBodyError?
} else if (Tok.is(tok::l_brace)) {
if (parseExprBrace(Body) || Body.isNull())
return 0; // FIXME: Need to call a new ActOnFuncBodyError?
}
// If this is a declaration, we're done.
if (Body.isNull())
return FD;
return S.decl.ActOnFuncBody(FD, Body.get());
}
/// parseDeclOneOf - Parse a 'oneof' declaration, returning null (and doing no
/// token skipping) on error.
///
/// decl-oneof:
/// 'oneof' attribute-list? identifier oneof-body
/// oneof-body:
/// '{' oneof-element-list '}'
/// oneof-element-list:
/// oneof-element ','?
/// oneof-element ',' oneof-element-list
/// oneof-element:
/// identifier
/// identifier ':' type
///
Decl *Parser::parseDeclOneOf() {
SMLoc OneOfLoc = Tok.getLoc();
consumeToken(tok::kw_oneof);
DeclAttributes Attributes;
if (Tok.is(tok::l_square))
parseAttributeList(Attributes);
SMLoc NameLoc = Tok.getLoc();
Identifier OneOfName;
Type OneOfType;
if (parseIdentifier(OneOfName, "expected identifier in oneof declaration"))
return 0;
TypeAliasDecl *TAD = S.decl.ActOnTypeAlias(NameLoc, OneOfName,
S.Context.TheUnresolvedType);
if (parseTypeOneOfBody(OneOfLoc, Attributes, OneOfType, TAD))
return 0;
return TAD;
}
/// parseDeclStruct - Parse a 'struct' declaration, returning null (and doing no
/// token skipping) on error. A 'struct' is just syntactic sugar for a oneof
/// with a single element.
///
/// decl-struct:
/// 'struct' attribute-list? identifier type-tuple
///
bool Parser::parseDeclStruct(llvm::SmallVectorImpl<ExprOrDecl> &Decls) {
SMLoc StructLoc = Tok.getLoc();
consumeToken(tok::kw_struct);
DeclAttributes Attributes;
if (Tok.is(tok::l_square))
parseAttributeList(Attributes);
Identifier StructName;
if (parseIdentifier(StructName, "expected identifier in struct declaration"))
return true;
Type Ty;
if (parseType(Ty)) return true;
// The type is required to be syntactically a tuple type.
if (!llvm::isa<TupleType>(Ty.getPointer())) {
error(StructLoc, "element type of struct is not a tuple");
// FIXME: Should set this as an erroroneous decl.
return true;
}
S.decl.ActOnStructDecl(StructLoc, Attributes, StructName, Ty, Decls);
return false;
}
//===----------------------------------------------------------------------===//
// Type Parsing
//===----------------------------------------------------------------------===//
/// parseType
/// type:
/// type-simple
/// type-function
/// type-array
///
/// type-function:
/// type-simple '->' type
///
/// type-array:
/// type '[' ']'
/// type '[' expr ']'
///
/// type-simple:
/// '__builtin_int32_type'
/// identifier
/// type-tuple
/// type-oneof
///
/// type-oneof:
/// 'oneof' attribute-list? oneof-body
///
bool Parser::parseType(Type &Result, const llvm::Twine &Message) {
// Parse type-simple first.
switch (Tok.getKind()) {
case tok::identifier:
Result = S.type.ActOnTypeName(Tok.getLoc(),
S.Context.getIdentifier(Tok.getText()));
consumeToken(tok::identifier);
break;
case tok::kw___builtin_int32_type:
Result = S.type.ActOnInt32Type(Tok.getLoc());
consumeToken(tok::kw___builtin_int32_type);
break;
case tok::l_paren:
if (parseTypeTuple(Result))
return true;
break;
case tok::kw_oneof: {
SMLoc OneOfLoc = Tok.getLoc();
consumeToken(tok::kw_oneof);
DeclAttributes Attributes;
if (Tok.is(tok::l_square))
parseAttributeList(Attributes);
if (parseTypeOneOfBody(OneOfLoc, Attributes, Result))
return true;
break;
}
default:
error(Tok.getLoc(), Message);
return true;
}
while (1) {
// If there is an arrow, parse the rest of the type.
SMLoc TokLoc = Tok.getLoc();
if (consumeIf(tok::arrow)) {
Type SecondHalf;
if (parseType(SecondHalf, "expected type in result of function type"))
return true;
Result = S.type.ActOnFunctionType(Result, TokLoc, SecondHalf);
continue;
}
// If there is a square bracket, we have an array.
if (consumeIf(tok::l_square)) {
llvm::NullablePtr<Expr> Size;
if (!Tok.is(tok::r_square) &&
parseExpr(Size, "expected expression for array type size"))
return true;
SMLoc RArrayTok = Tok.getLoc();
if (parseToken(tok::r_square, "expected ']' in array type")) {
note(TokLoc, "to match this '['");
return true;
}
Result = S.type.ActOnArrayType(Result, TokLoc, Size.getPtrOrNull(),
RArrayTok);
continue;
}
break;
}
return false;
}
bool Parser::parseType(Type &Result) {
return parseType(Result, "expected type");
}
/// parseTypeTuple
/// type-tuple:
/// '(' ')'
/// '(' identifier? value-specifier (',' identifier? value-specifier)* ')'
///
bool Parser::parseTypeTuple(Type &Result) {
assert(Tok.is(tok::l_paren) && "Not start of type tuple");
SMLoc LPLoc = Tok.getLoc();
consumeToken(tok::l_paren);
llvm::SmallVector<TupleTypeElt, 8> Elements;
if (Tok.isNot(tok::r_paren)) {
bool HadError = false;
do {
Elements.push_back(TupleTypeElt());
TupleTypeElt &Result = Elements.back();
if (Tok.is(tok::identifier))
parseIdentifier(Result.Name, "");
NullablePtr<Expr> Init;
if ((HadError = parseValueSpecifier(Result.Ty, Init)))
break;
Result.Init = Init.getPtrOrNull();
} while (consumeIf(tok::comma));
if (HadError) {
skipUntil(tok::r_paren);
if (Tok.is(tok::r_paren))
consumeToken(tok::r_paren);
return true;
}
}
SMLoc RPLoc = Tok.getLoc();
if (parseToken(tok::r_paren, "expected ')' at end of tuple list",
tok::r_paren)) {
note(LPLoc, "to match this opening '('");
return true;
}
Result = S.type.ActOnTupleType(LPLoc, Elements, RPLoc);
return false;
}
/// oneof-body:
/// '{' oneof-element-list '}'
/// oneof-element-list:
/// oneof-element ','?
/// oneof-element ',' oneof-element-list
/// oneof-element:
/// identifier
/// identifier ':' type
///
/// If TypeName is specified, it is the type that the constructors should be
/// built with, so that they preserve the name of the oneof decl that contains
/// this.
bool Parser::parseTypeOneOfBody(SMLoc OneOfLoc, const DeclAttributes &Attrs,
Type &Result, TypeAliasDecl *TypeName) {
if (parseToken(tok::l_brace, "expected '{' in oneof type"))
return true;
llvm::SmallVector<SemaType::OneOfElementInfo, 8> ElementInfos;
// Parse the comma separated list of oneof elements.
while (Tok.is(tok::identifier)) {
SemaType::OneOfElementInfo ElementInfo;
ElementInfo.Name = Tok.getText();
ElementInfo.NameLoc = Tok.getLoc();
ElementInfo.EltType = 0;
consumeToken(tok::identifier);
// See if we have a type specifier for this oneof element. If so, parse it.
if (consumeIf(tok::colon) &&
parseType(ElementInfo.EltType,
"expected type while parsing oneof element '" +
ElementInfo.Name + "'")) {
skipUntil(tok::r_brace);
return true;
}
ElementInfos.push_back(ElementInfo);
// Require comma separation.
if (!consumeIf(tok::comma))
break;
}
parseToken(tok::r_brace, "expected '}' at end of oneof");
Result = S.type.ActOnOneOfType(OneOfLoc, Attrs, ElementInfos, TypeName);
return false;
}
//===----------------------------------------------------------------------===//
// Expression Parsing
//===----------------------------------------------------------------------===//
static bool isStartOfExpr(Token &Tok) {
return Tok.is(tok::numeric_constant) || Tok.is(tok::colon) ||
Tok.is(tok::l_paren) || Tok.is(tok::l_brace) ||
Tok.is(tok::dollarident) || Tok.is(tok::identifier);
}
/// parseExpr
/// expr:
/// expr-primary+
bool Parser::parseExpr(NullablePtr<Expr> &Result, const char *Message) {
llvm::SmallVector<Expr*, 8> SequencedExprs;
do {
// Parse the expr-primary.
Result = 0;
if (parseExprPrimary(Result) || Result.isNull()) return true;
SequencedExprs.push_back(Result.get());
} while (isStartOfExpr(Tok));
// If there is exactly one element in the sequence, it is a degenerate
// sequence that just returns the last value anyway, shortcut ActOnSequence.
if (SequencedExprs.size() == 1) {
Result = SequencedExprs[0];
return false;
}
assert(!SequencedExprs.empty() && "Empty sequence isn't possible");
Expr **NewElements =
S.Context.AllocateCopy<Expr*>(SequencedExprs.begin(), SequencedExprs.end());
Result = new (S.Context) SequenceExpr(NewElements, SequencedExprs.size());
return false;
}
/// parseExprPrimary
/// expr-primary:
/// expr-literal
/// expr-identifier
/// ':' identifier
/// expr-paren
/// expr-brace
/// expr-field
/// expr-subscript
/// expr-primary-fn expr-primary
///
/// expr-literal:
/// numeric_constant
///
/// expr-primary-fn:
/// expr-primary Type sensitive: iff expr has fn type
///
/// expr-field:
/// expr-primary '.' identifier
/// expr-primary '.' dollarident
///
/// expr-subscript:
/// expr-primary '[' expr ']'
bool Parser::parseExprPrimary(NullablePtr<Expr> &Result, const char *Message) {
switch (Tok.getKind()) {
case tok::numeric_constant:
Result = S.expr.ActOnNumericConstant(Tok.getText(), Tok.getLoc());
consumeToken(tok::numeric_constant);
break;
case tok::dollarident: // $1
if (parseExprDollarIdentifier(Result)) return true;
break;
case tok::identifier: // foo and foo::bar
if (parseExprIdentifier(Result)) return true;
break;
case tok::colon: { // :foo
SMLoc ColonLoc = Tok.getLoc();
consumeToken(tok::colon);
Identifier Name;
SMLoc NameLoc = Tok.getLoc();
if (parseIdentifier(Name, "expected identifier after ':' expression"))
return true;
// Handle :foo by just making an AST node.
Result = new (S.Context) UnresolvedMemberExpr(ColonLoc, NameLoc, Name);
break;
}
case tok::l_paren:
if (parseExprParen(Result)) return true;
break;
case tok::l_brace:
if (parseExprBrace(Result)) return true;
break;
default:
error(Tok.getLoc(), Message ? Message : "expected expression");
return true;
}
// Handle suffix expressions.
while (1) {
// Check for a .foo suffix.
SMLoc TokLoc = Tok.getLoc();
if (consumeIf(tok::period)) {
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::dollarident)) {
error(Tok.getLoc(), "expected field name");
return true;
}
if (!Result.isNull()) {
Identifier Name = S.Context.getIdentifier(Tok.getText());
Result = new (S.Context) UnresolvedDotExpr(Result.get(), TokLoc,
Name, Tok.getLoc());
}
if (Tok.is(tok::identifier))
consumeToken(tok::identifier);
else
consumeToken(tok::dollarident);
continue;
}
// Check for a [expr] suffix.
if (consumeIf(tok::l_square)) {
NullablePtr<Expr> Idx;
if (parseExpr(Idx, "expected expression parsing array index"))
return true;
SMLoc RLoc = Tok.getLoc();
if (parseToken(tok::r_square, "expected ']'")) {
note(TokLoc, "to match this '['");
return true;
}
if (!Result.isNull() && !Idx.isNull())
Result = S.expr.ActOnArraySubscript(Result.get(), TokLoc, Idx.get(),
RLoc);
}
break;
}
return false;
}
/// expr-identifier:
/// dollarident
bool Parser::parseExprDollarIdentifier(llvm::NullablePtr<Expr> &Result) {
llvm::StringRef Name = Tok.getText();
SMLoc Loc = Tok.getLoc();
consumeToken(tok::dollarident);
assert(Name[0] == '$' && "Not a dollarident");
bool AllNumeric = true;
for (unsigned i = 1, e = Name.size(); i != e; ++i)
AllNumeric &= isdigit(Name[i]);
if (Name.size() == 1 || !AllNumeric) {
error(Loc, "invalid identifier, expected expression");
return true;
}
unsigned ArgNo = 0;
if (Name.substr(1).getAsInteger(10, ArgNo)) {
error(Loc, "invalid name in $ expression");
return true;
}
Result = new (S.Context) AnonClosureArgExpr(ArgNo, Loc);
return false;
}
/// parseExprIdentifier - Parse an identifier expression:
///
/// expr-identifier:
/// identifier
/// identifier '::' identifier
bool Parser::parseExprIdentifier(llvm::NullablePtr<Expr> &Result) {
assert(Tok.is(tok::identifier));
SMLoc Loc = Tok.getLoc();
Identifier Name;
parseIdentifier(Name, "");
if (Tok.isNot(tok::coloncolon)) {
Result = S.expr.ActOnIdentifierExpr(Name, Loc);
return false;
}
SMLoc ColonColonLoc = Tok.getLoc();
consumeToken(tok::coloncolon);
SMLoc Loc2 = Tok.getLoc();
Identifier Name2;
if (parseIdentifier(Name2, "expected identifier after '" + Name.str() +
"::' expression"))
return true;
Result = S.expr.ActOnScopedIdentifierExpr(Name, Loc, ColonColonLoc,
Name2, Loc2);
return false;
}
/// parseExprParen - Parse a tuple expression.
///
/// expr-paren:
/// '(' ')'
/// '(' expr-paren-element (',' expr-paren-element)* ')'
///
/// expr-paren-element:
/// ('.' identifier '=')? expr
///
bool Parser::parseExprParen(llvm::NullablePtr<Expr> &Result) {
SMLoc LPLoc = Tok.getLoc();
consumeToken(tok::l_paren);
llvm::SmallVector<Expr*, 8> SubExprs;
llvm::SmallVector<Identifier, 8> SubExprNames;
bool AnyErroneousSubExprs = false;
if (Tok.isNot(tok::r_paren)) {
do {
Identifier FieldName;
// Check to see if there is a field specifier.
if (consumeIf(tok::period)) {
if (parseIdentifier(FieldName,
"expected field specifier name in tuple expression")||
parseToken(tok::equal, "expected '=' in tuple expression"))
return true;
}
if (!SubExprNames.empty())
SubExprNames.push_back(FieldName);
else if (FieldName.get()) {
SubExprNames.resize(SubExprs.size());
SubExprNames.push_back(FieldName);
}
NullablePtr<Expr> SubExpr;
if (parseExpr(SubExpr, "expected expression in parentheses")) return true;
if (SubExpr.isNull())
AnyErroneousSubExprs = true;
else
SubExprs.push_back(SubExpr.get());
} while (consumeIf(tok::comma));
}
SMLoc RPLoc = Tok.getLoc();
if (parseToken(tok::r_paren, "expected ')' in parenthesis expression")) {
note(LPLoc, "to match this opening '('");
return true;
}
if (AnyErroneousSubExprs)
return false;
// Determine whether the left paren was immediately preceded by an identifier,
// as in 'foo()', which indicates that the tuple needs to be bound to that
// identifier somehow. This is a highly skanky way to get this, but it works
// reasonably well.
bool IsPrecededByIdentifier = L.isPrecededByIdentifier(LPLoc);
Result = S.expr.ActOnTupleExpr(LPLoc, SubExprs.data(),
SubExprNames.empty()?0 : SubExprNames.data(),
SubExprs.size(), RPLoc,
IsPrecededByIdentifier);
return false;
}
/// parseExprBrace - A brace enclosed expression list which may optionally end
/// with a ; inside of it. For example { 1; 4+5; } or { 1; 2 }.
///
/// expr-brace:
/// '{' expr-brace-item* '}'
/// expr-brace-item:
/// expr
/// expr '=' expr
/// decl-var
/// decl-oneof
/// decl-struct
/// decl-typealias
/// ';'
bool Parser::parseExprBrace(llvm::NullablePtr<Expr> &Result) {
SMLoc LBLoc = Tok.getLoc();
consumeToken(tok::l_brace);
llvm::SmallVector<ExprOrDecl, 16> Entries;
// MissingSemiAtEnd - Keep track of whether the last expression in the block
// had no semicolon.
bool MissingSemiAtEnd = false;
if (parseDeclExprList(Entries, MissingSemiAtEnd, false /*NotTopLevel*/))
return true;
SMLoc RBLoc = Tok.getLoc();
if (parseToken(tok::r_brace, "expected '}' at end of brace expression",
tok::r_brace)) {
note(LBLoc, "to match this opening '{'");
return true;
}
ExprOrDecl *NewElements =
S.Context.AllocateCopy<ExprOrDecl>(Entries.begin(), Entries.end());
Result = new (S.Context) BraceExpr(LBLoc, NewElements, Entries.size(),
MissingSemiAtEnd, RBLoc);
return false;
}
/// expr-brace-item:
/// expr
/// expr '=' expr
/// decl-var
/// decl-oneof
/// decl-struct
/// decl-typealias
/// ';'
bool Parser::parseDeclExprList(llvm::SmallVectorImpl<ExprOrDecl> &Entries,
bool &MissingSemiAtEnd, bool IsTopLevel) {
// This forms a lexical scope.
Scope BraceScope(S.decl);
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
MissingSemiAtEnd = false;
// Parse the decl or expression.
switch (Tok.getKind()) {
case tok::semi:
// Could create a decl for semicolons if we care.
consumeToken(tok::semi);
continue;
case tok::kw_import:
Entries.push_back(parseDeclImport());
if (Entries.back() && !IsTopLevel) {
error(Entries.back().get<Decl*>()->getLocStart(),
"import is only valid at file scope");
Entries.pop_back();
}
break;
case tok::kw_var:
parseDeclVar(Entries);
break;
case tok::kw_func:
Entries.push_back(parseDeclFunc());
break;
case tok::kw_typealias:
Entries.push_back(parseDeclTypeAlias());
break;
case tok::kw_oneof:
Entries.push_back(parseDeclOneOf());
break;
case tok::kw_struct:
parseDeclStruct(Entries);
break;
default:
Entries.push_back(ExprOrDecl());
NullablePtr<Expr> ResultExpr;
if (parseExpr(ResultExpr) || ResultExpr.isNull())
break;
// FIXME: Assignment is a hack until we get generics. We really want to
// parse '=' as any other overloaded/generic binary operator.
if (Tok.is(tok::equal)) {
SMLoc EqualLoc = Tok.getLoc();
consumeToken();
NullablePtr<Expr> RHSExpr;
if (parseExpr(RHSExpr) || RHSExpr.isNull())
break;
// FIXME: Assignment is represented with null Fn.
ResultExpr = new (S.Context) BinaryExpr(ResultExpr.get(), 0, EqualLoc,
RHSExpr.get());
}
Entries.back() = ResultExpr.get();
MissingSemiAtEnd = true;
break;
}
if (Entries.back().isNull()) {
Entries.pop_back();
if (Tok.is(tok::semi))
continue; // Consume the ';' and keep going.
// FIXME: QOI: Improve error recovery.
if (Tok.is(tok::semi) && Tok.isNot(tok::r_brace))
skipUntil(tok::r_brace);
consumeIf(tok::r_brace);
return true;
}
}
return false;
}