Files
swift-mirror/include/swift/Parse/Parser.h
Doug Gregor d762dd53f8 Stop parsing into IfConfiDecl nodes in the C++ parser
When parsing #if...#endif regions, parse the active clause directly into
place in the AST without ever producing an IfConfigDecl instance.
2024-09-18 20:51:09 -07:00

2238 lines
86 KiB
C++

//===--- Parser.h - Swift Language Parser -----------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the Parser interface.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_PARSER_H
#define SWIFT_PARSER_H
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTNode.h"
#include "swift/AST/DiagnosticsParse.h"
#include "swift/AST/Expr.h"
#include "swift/AST/LayoutConstraint.h"
#include "swift/AST/LifetimeDependence.h"
#include "swift/AST/ParseRequests.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/Stmt.h"
#include "swift/Basic/OptionSet.h"
#include "swift/Config.h"
#include "swift/Parse/Lexer.h"
#include "swift/Parse/ParserPosition.h"
#include "swift/Parse/ParserResult.h"
#include "swift/Parse/PatternBindingState.h"
#include "swift/Parse/PersistentParserState.h"
#include "swift/Parse/Token.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
namespace llvm {
template <typename... PTs> class PointerUnion;
}
namespace swift {
class CodeCompletionCallbacks;
class DoneParsingCallback;
class DefaultArgumentInitializer;
class DiagnosticEngine;
class Expr;
class Lexer;
class PersistentParserState;
class RequirementRepr;
class SILParserStateBase;
class SourceManager;
class UUID;
struct EnumElementInfo;
/// Different contexts in which BraceItemList are parsed.
enum class BraceItemListKind {
/// A statement list terminated by a closing brace. The default.
Brace,
/// A statement list in a case block. The list is terminated
/// by a closing brace or a 'case' or 'default' label.
Case,
/// The top-level of a file, when not in parse-as-library mode (i.e. the
/// repl or a script).
TopLevelCode,
/// The top-level of a file, when in parse-as-library mode.
TopLevelLibrary,
/// The body of the inactive clause of an #if/#else/#endif block
InactiveConditionalBlock,
/// The body of the active clause of an #if/#else/#endif block
ActiveConditionalBlock,
/// The top-level of a macro expansion "file".
MacroExpansion,
};
/// The receiver will be fed with consumed tokens while parsing. The main purpose
/// is to generate a corrected token stream for tooling support like syntax
/// coloring.
class ConsumeTokenReceiver {
public:
/// This is called when a token is consumed.
virtual void receive(const Token &Tok) {}
/// This is called to update the kind of a token whose start location is Loc.
virtual void registerTokenKindChange(SourceLoc Loc, tok NewKind) {};
/// This is called when a source file is fully parsed. It returns the
/// finalized vector of tokens, or \c None if the receiver isn't configured to
/// record them.
virtual std::optional<std::vector<Token>> finalize() { return std::nullopt; }
virtual ~ConsumeTokenReceiver() = default;
};
/// The role of the elements in a given #if
enum class IfConfigElementsRole {
// Parse normally.
Normal,
// Parse, but only for syntax. Throw away the results.
SyntaxOnly,
// Already skipped; no need to parse anything.
Skipped
};
/// Describes the context in which the '#if' is being parsed.
enum class IfConfigContext {
BraceItems,
DeclItems,
SwitchStmt,
PostfixExpr,
DeclAttrs
};
/// The main class used for parsing a source file (.swift or .sil).
///
/// Rather than instantiating a Parser yourself, use one of the parsing APIs
/// provided in Subsystems.h.
class Parser {
Parser(const Parser&) = delete;
void operator=(const Parser&) = delete;
bool IsInputIncomplete = false;
bool EnableParameterizedNonisolated = true; // HACK: for closures
std::vector<Token> SplitTokens;
public:
SourceManager &SourceMgr;
DiagnosticEngine &Diags;
SourceFile &SF;
Lexer *L;
SILParserStateBase *SIL; // Non-null when parsing SIL decls.
PersistentParserState *State;
std::unique_ptr<PersistentParserState> OwnedState;
DeclContext *CurDeclContext;
ASTContext &Context;
CodeCompletionCallbacks *CodeCompletionCallbacks = nullptr;
DoneParsingCallback *DoneParsingCallback = nullptr;
std::vector<Located<std::vector<ParamDecl*>>> AnonClosureVars;
/// The current token hash, or \c None if the parser isn't computing a hash
/// for the token stream.
std::optional<StableHasher> CurrentTokenHash;
void recordTokenHash(const Token Tok) {
if (!Tok.getText().empty())
recordTokenHash(Tok.getText());
}
void recordTokenHash(StringRef token);
PatternBindingState InBindingPattern = PatternBindingState::NotInBinding;
/// Whether this context has an async attribute.
bool InPatternWithAsyncAttribute = false;
/// Whether a '#sourceLocation' is currently active.
/// NOTE: Do not use this outside of `parseLineDirective`, it doesn't have
/// its state restored when parsing delayed bodies (we avoid skipping bodies
/// if we see a `#sourceLocation` in them though). Instead, query the
/// SourceManager.
bool InPoundLineEnvironment = false;
bool InPoundIfEnvironment = false;
/// ASTScopes are not created in inactive clauses and lookups to decls will fail.
bool InInactiveClauseEnvironment = false;
bool InSwiftKeyPath = false;
bool InFreestandingMacroArgument = false;
/// This Parser is a fallback parser for ASTGen.
// Note: This doesn't affect anything in non-SWIFT_BUILD_SWIFT_SYNTAX envs.
bool IsForASTGen = false;
/// Whether we should delay parsing nominal type, extension, and function
/// bodies.
bool isDelayedParsingEnabled() const;
/// Whether to evaluate the conditions of #if decls, meaning that the bodies
/// of any active clauses are hoisted such that they become sibling nodes with
/// the #if decl.
bool shouldEvaluatePoundIfDecls() const;
void setCodeCompletionCallbacks(class CodeCompletionCallbacks *Callbacks) {
CodeCompletionCallbacks = Callbacks;
}
void setDoneParsingCallback(class DoneParsingCallback *Callback) {
this->DoneParsingCallback = Callback;
}
bool isIDEInspectionFirstPass() const {
return SourceMgr.hasIDEInspectionTargetBuffer() && !DoneParsingCallback;
}
bool allowTopLevelCode() const;
bool isInMacroExpansion(SourceLoc loc) const;
const std::vector<Token> &getSplitTokens() const { return SplitTokens; }
void markSplitToken(tok Kind, StringRef Txt);
/// Returns true if the parser reached EOF with incomplete source input, due
/// for example, a missing right brace.
bool isInputIncomplete() const { return IsInputIncomplete; }
void checkForInputIncomplete() {
IsInputIncomplete = IsInputIncomplete ||
// Check whether parser reached EOF but the real EOF, not the end of a
// string interpolation segment.
(Tok.is(tok::eof) && Tok.getText() != ")");
}
/// This is the current token being considered by the parser.
Token Tok;
/// The receiver to collect all consumed tokens.
ConsumeTokenReceiver *TokReceiver;
/// The location of the previous token.
SourceLoc PreviousLoc;
/// Use this to assert that the parser has advanced the lexing location, e.g.
/// before a specific parser function has returned.
class AssertParserMadeProgressBeforeLeavingScopeRAII {
Parser &P;
SourceLoc InitialLoc;
public:
AssertParserMadeProgressBeforeLeavingScopeRAII(Parser &parser) : P(parser) {
InitialLoc = P.Tok.getLoc();
}
~AssertParserMadeProgressBeforeLeavingScopeRAII() {
assert(InitialLoc != P.Tok.getLoc() &&
"parser did not make progress, this can result in infinite loop");
}
};
/// A RAII object for temporarily changing CurDeclContext.
class ContextChange {
protected:
Parser &P;
DeclContext *OldContext; // null signals that this has been popped
ContextChange(const ContextChange &) = delete;
ContextChange &operator=(const ContextChange &) = delete;
public:
ContextChange(Parser &P, DeclContext *DC)
: P(P), OldContext(P.CurDeclContext) {
assert(DC && "pushing null context?");
P.CurDeclContext = DC;
}
/// Prematurely pop the DeclContext installed by the constructor.
/// Makes the destructor a no-op.
void pop() {
assert(OldContext && "already popped context!");
popImpl();
OldContext = nullptr;
}
~ContextChange() {
if (OldContext) popImpl();
}
private:
void popImpl() {
P.CurDeclContext = OldContext;
}
};
/// A RAII object for parsing a new local context.
class ParseFunctionBody {
private:
ContextChange CC;
public:
ParseFunctionBody(Parser &P, DeclContext *DC) : CC(P, DC) {
assert(!isa<TopLevelCodeDecl>(DC) &&
"top-level code should be parsed using TopLevelCodeContext!");
}
void pop() {
CC.pop();
}
};
/// Describes the kind of a lexical structure marker, indicating
/// what kind of structural element we started parsing at a
/// particular location.
enum class StructureMarkerKind : uint8_t {
/// The start of a declaration.
Declaration,
/// The start of a statement.
Statement,
/// An open parentheses.
OpenParen,
/// An open brace.
OpenBrace,
/// An open square bracket.
OpenSquare,
/// An #if conditional clause.
IfConfig,
};
/// A structure marker, which identifies the location at which the
/// parser saw an entity it is parsing.
struct StructureMarker {
/// The location at which the marker occurred.
SourceLoc Loc;
/// The kind of marker.
StructureMarkerKind Kind;
/// The leading whitespace for this marker, if it has already been
/// computed.
std::optional<StringRef> LeadingWhitespace;
};
/// An RAII object that notes when we have seen a structure marker.
class StructureMarkerRAII {
Parser &P;
/// Max nesting level
// TODO: customizable.
enum { MaxDepth = 256 };
StructureMarkerRAII(Parser &parser) : P(parser) {}
public:
StructureMarkerRAII(Parser &parser, SourceLoc loc,
StructureMarkerKind kind);
StructureMarkerRAII(Parser &parser, const Token &tok);
~StructureMarkerRAII() { P.StructureMarkers.pop_back(); }
};
friend class StructureMarkerRAII;
/// The stack of structure markers indicating the locations of
/// structural elements actively being parsed, including the start
/// of declarations, statements, and opening operators of various
/// kinds.
///
/// This vector is managed by \c StructureMarkerRAII objects.
llvm::SmallVector<StructureMarker, 16> StructureMarkers;
/// Maps of macro name and version to availability specifications.
typedef llvm::DenseMap<llvm::VersionTuple,
SmallVector<AvailabilitySpec *, 4>>
AvailabilityMacroVersionMap;
typedef llvm::DenseMap<StringRef, AvailabilityMacroVersionMap>
AvailabilityMacroMap;
/// Cache of the availability macros parsed from the command line arguments.
/// Organized as two nested \c DenseMap keyed first on the macro name then
/// the macro version. This structure allows to peek at macro names before
/// parsing a version tuple.
AvailabilityMacroMap AvailabilityMacros;
/// Has \c AvailabilityMacros been computed?
bool AvailabilityMacrosComputed = false;
public:
Parser(unsigned BufferID, SourceFile &SF, DiagnosticEngine* LexerDiags,
SILParserStateBase *SIL, PersistentParserState *PersistentState);
Parser(unsigned BufferID, SourceFile &SF, SILParserStateBase *SIL,
PersistentParserState *PersistentState = nullptr);
Parser(std::unique_ptr<Lexer> Lex, SourceFile &SF,
SILParserStateBase *SIL = nullptr,
PersistentParserState *PersistentState = nullptr);
~Parser();
/// Returns true if the buffer being parsed is allowed to contain SIL.
bool isInSILMode() const;
/// Retrieve the token receiver from the parser once it has finished parsing.
std::unique_ptr<ConsumeTokenReceiver> takeTokenReceiver() {
assert(Tok.is(tok::eof) && "not done parsing yet");
auto *receiver = TokReceiver;
TokReceiver = nullptr;
return std::unique_ptr<ConsumeTokenReceiver>(receiver);
}
//===--------------------------------------------------------------------===//
// Routines to save and restore parser state.
ParserPosition getParserPosition() {
return ParserPosition(L->getStateForBeginningOfToken(Tok),
PreviousLoc);
}
ParserPosition getParserPosition(SourceLoc loc, SourceLoc previousLoc) {
return ParserPosition(L->getStateForBeginningOfTokenLoc(loc), previousLoc);
}
void restoreParserPosition(ParserPosition PP, bool enableDiagnostics = false) {
L->restoreState(PP.LS, enableDiagnostics);
L->lex(Tok);
PreviousLoc = PP.PreviousLoc;
}
void backtrackToPosition(ParserPosition PP) {
assert(PP.isValid());
L->backtrackToState(PP.LS);
L->lex(Tok);
PreviousLoc = PP.PreviousLoc;
}
/// RAII object that, when it is destructed, restores the parser and lexer to
/// their positions at the time the object was constructed. Will not jump
/// forward in the token stream.
/// Actual uses of the backtracking scope should choose either \c
/// BacktrackingScope, which will always backtrack or \c
/// CancellableBacktrackingScope which can be cancelled.
class BacktrackingScopeImpl {
protected:
Parser &P;
ParserPosition PP;
DiagnosticTransaction DT;
bool Backtrack = true;
/// A token receiver used by the parser in the back tracking scope. This
/// receiver will save any consumed tokens during this back tracking scope.
/// After the scope ends, it either transfers the saved tokens to the old receiver
/// or discard them.
struct DelayedTokenReceiver: ConsumeTokenReceiver {
/// Keep track of the old token receiver in the parser so that we can recover
/// after the backtracking sope ends.
llvm::SaveAndRestore<ConsumeTokenReceiver*> savedConsumer;
// Whether the tokens should be transferred to the original receiver.
// When the back tracking scope will actually back track, this should be false;
// otherwise true.
bool shouldTransfer = false;
std::vector<Token> delayedTokens;
DelayedTokenReceiver(ConsumeTokenReceiver *&receiver):
savedConsumer(receiver, this) {}
void receive(const Token &tok) override { delayedTokens.push_back(tok); }
std::optional<std::vector<Token>> finalize() override {
llvm_unreachable("Cannot finalize a DelayedTokenReceiver");
}
~DelayedTokenReceiver() {
if (!shouldTransfer)
return;
for (auto tok: delayedTokens) {
savedConsumer.get()->receive(tok);
}
}
} TempReceiver;
BacktrackingScopeImpl(Parser &P)
: P(P), PP(P.getParserPosition()), DT(P.Diags),
TempReceiver(P.TokReceiver) { }
public:
~BacktrackingScopeImpl();
bool willBacktrack() const { return Backtrack; }
};
/// A backtracking scope that will always backtrack when destructed.
class BacktrackingScope final : public BacktrackingScopeImpl {
public:
BacktrackingScope(Parser &P) : BacktrackingScopeImpl(P) { }
};
/// A backtracking scope whose backtracking can be disabled by calling
/// \c cancelBacktrack.
class CancellableBacktrackingScope final : public BacktrackingScopeImpl {
public:
CancellableBacktrackingScope(Parser &P) : BacktrackingScopeImpl(P) { }
void cancelBacktrack();
};
/// RAII object that, when it is destructed, restores the parser and lexer to
/// their positions at the time the object was constructed.
struct ParserPositionRAII {
private:
Parser &P;
ParserPosition PP;
public:
ParserPositionRAII(Parser &P) : P(P), PP(P.getParserPosition()) {}
~ParserPositionRAII() {
P.restoreParserPosition(PP);
}
};
//===--------------------------------------------------------------------===//
// Utilities
/// Return the next token that will be installed by \c consumeToken.
const Token &peekToken();
/// Consumes K tokens within a backtracking scope before calling \c f and
/// providing it with the backtracking scope. Unless if the backtracking is
/// explicitly cancelled, the parser's token state is restored after \c f
/// returns.
///
/// \param K The number of tokens ahead to skip. Zero is the current token.
/// \param f The function to apply after skipping K tokens ahead.
/// The value returned by \c f will be returned by \c peekToken
/// after the parser is rolled back.
/// \returns the value returned by \c f
/// \note When calling, you may need to specify the \c Val type
/// explicitly as a type parameter.
template <typename Val>
Val lookahead(unsigned char K,
llvm::function_ref<Val(CancellableBacktrackingScope &)> f) {
CancellableBacktrackingScope backtrackScope(*this);
for (unsigned char i = 0; i < K; ++i)
consumeToken();
return f(backtrackScope);
}
/// Discard the current token. This will avoid interface hashing or updating
/// the previous loc. Only should be used if you've completely re-lexed
/// a different token at that position.
SourceLoc discardToken();
/// Consume a token that we created on the fly to correct the original token
/// stream from lexer.
void consumeExtraToken(Token K);
SourceLoc consumeTokenWithoutFeedingReceiver();
SourceLoc consumeToken();
SourceLoc consumeToken(tok K) {
assert(Tok.is(K) && "Consuming wrong token kind");
return consumeToken();
}
SourceLoc consumeIdentifier(Identifier &Result, bool diagnoseDollarPrefix) {
assert(Tok.isAny(tok::identifier, tok::kw_self, tok::kw_Self));
assert(Result.empty());
Result = Context.getIdentifier(Tok.getText());
if (Tok.getText()[0] == '$')
diagnoseDollarIdentifier(Tok, diagnoseDollarPrefix);
return consumeToken();
}
SourceLoc consumeArgumentLabel(Identifier &Result,
bool diagnoseDollarPrefix) {
assert(Tok.canBeArgumentLabel());
assert(Result.empty());
if (!Tok.is(tok::kw__)) {
Tok.setKind(tok::identifier);
Result = Context.getIdentifier(Tok.getText());
if (Tok.getText()[0] == '$')
diagnoseDollarIdentifier(Tok, diagnoseDollarPrefix);
}
return consumeToken();
}
/// When we have a token that is an identifier starting with '$',
/// diagnose it if not permitted in this mode.
/// \param diagnoseDollarPrefix Whether to diagnose dollar-prefixed
/// identifiers in addition to a standalone '$'.
void diagnoseDollarIdentifier(const Token &tok,
bool diagnoseDollarPrefix) {
assert(tok.getText()[0] == '$');
// If '$' is not guarded by backticks, offer
// to replace it with '`$`'.
if (Tok.getRawText() == "$") {
diagnose(Tok.getLoc(), diag::standalone_dollar_identifier)
.fixItReplace(Tok.getLoc(), "`$`");
return;
}
if (!diagnoseDollarPrefix)
return;
if (tok.getText().size() == 1 || Context.LangOpts.EnableDollarIdentifiers ||
isInSILMode() || L->isSwiftInterface() ||
isInMacroExpansion(tok.getLoc()))
return;
diagnose(tok.getLoc(), diag::dollar_identifier_decl,
Context.getIdentifier(tok.getText()));
}
/// Retrieve the location just past the end of the previous
/// source location.
SourceLoc getEndOfPreviousLoc() const;
/// If the current token is the specified kind, consume it and
/// return true. Otherwise, return false without consuming it.
bool consumeIf(tok K) {
if (Tok.isNot(K)) return false;
consumeToken(K);
return true;
}
/// If the current token is the specified kind, consume it and
/// return true. Otherwise, return false without consuming it.
bool consumeIf(tok K, SourceLoc &consumedLoc) {
if (Tok.isNot(K)) return false;
consumedLoc = consumeToken(K);
return true;
}
/// Consume a '('. If it is not directly following the previous token, emit an
/// error (Swift 6) or warning (Swift <6) that attribute name and parentheses
/// must not be separated by a space.
SourceLoc consumeAttributeLParen();
/// If the next token is a '(' that's not on a new line consume it, and error
/// (Swift 6) or warn (Swift <6) that the attribute must not be separted from
/// the '(' by a space.
///
/// If the next token is not '(' or it's on a new line, return false.
bool consumeIfAttributeLParen();
bool consumeIfNotAtStartOfLine(tok K) {
if (Tok.isAtStartOfLine()) return false;
return consumeIf(K);
}
bool isContextualYieldKeyword() {
return (Tok.isContextualKeyword("yield") &&
isa<AccessorDecl>(CurDeclContext) &&
cast<AccessorDecl>(CurDeclContext)->isCoroutine());
}
/// Whether the current token is the contextual keyword for a \c then
/// statement.
bool isContextualThenKeyword(bool preferExpr);
/// `discard self` is the only valid phrase, but we peek ahead for just any
/// identifier after `discard` to determine if it's the statement. This helps
/// us avoid interpreting `discard(self)` as the statement and not a call.
/// We also want to be mindful of statements like `discard ++ something` where
/// folks have defined a custom operator returning void.
///
/// Later, type checking will verify that you're discarding the right thing
/// so that when people make a mistake, thinking they can `discard x` we give
/// a nice diagnostic.
bool isContextualDiscardKeyword() {
// must be `discard` ...
if (!Tok.isContextualKeyword("discard"))
return false;
// followed by either an identifier, `self`, or `Self`.
return !peekToken().isAtStartOfLine()
&& peekToken().isAny(tok::identifier, tok::kw_self, tok::kw_Self);
}
/// Read tokens until we get to one of the specified tokens, then
/// return without consuming it. Because we cannot guarantee that the token
/// will ever occur, this skips to some likely good stopping point.
ParserStatus skipUntil(tok T1, tok T2 = tok::NUM_TOKENS);
void skipUntilAnyOperator();
/// Skip until a token that starts with '>', and consume it if found.
/// Applies heuristics that are suitable when trying to find the end of a list
/// of generic parameters, generic arguments, or list of types in a protocol
/// composition.
SourceLoc skipUntilGreaterInTypeList(bool protocolComposition = false);
/// skipUntilDeclStmtRBrace - Skip to the next decl or '}'.
void skipUntilDeclRBrace();
template <typename ...T>
void skipUntilDeclStmtRBrace(T... K) {
while (Tok.isNot(K..., tok::eof, tok::r_brace, tok::pound_endif,
tok::pound_else, tok::pound_elseif,
tok::code_complete) &&
!isStartOfStmt(/*preferExpr*/ false) &&
!isStartOfSwiftDecl(/*allowPoundIfAttributes=*/true)) {
skipSingle();
}
}
void skipUntilDeclRBrace(tok T1, tok T2);
void skipListUntilDeclRBrace(SourceLoc startLoc, tok T1, tok T2);
/// Skip a single token, but match parentheses, braces, and square brackets.
///
/// Note: this does \em not match angle brackets ("<" and ">")! These are
/// matched in the source when they refer to a generic type,
/// but not when used as comparison operators.
///
/// Returns a parser status that can capture whether a code completion token
/// was returned.
ParserStatus skipSingle();
/// Skip until the next '#else', '#endif' or until eof.
void skipUntilConditionalBlockClose();
/// Skip until either finding \c T1 or reaching the end of the line.
///
/// This uses \c skipSingle and so matches parens etc. After calling, one or
/// more of the following will be true: Tok.is(T1), Tok.isStartOfLine(),
/// Tok.is(tok::eof). The "or more" case is the first two: if the next line
/// starts with T1.
///
/// \returns true if there is an instance of \c T1 on the current line (this
/// avoids the foot-gun of not considering T1 starting the next line for a
/// plain Tok.is(T1) check).
bool skipUntilTokenOrEndOfLine(tok T1, tok T2 = tok::NUM_TOKENS);
/// Skip over SIL decls until we encounter the start of a Swift decl or eof.
void skipSILUntilSwiftDecl();
/// Skip over any attribute.
void skipAnyAttribute();
/// Parse an #endif.
bool parseEndIfDirective(SourceLoc &Loc);
/// Given that the current token is a string literal,
/// - if it is not interpolated, returns the contents;
/// - otherwise, diagnoses and returns None.
///
/// \param Loc where to diagnose.
/// \param DiagText name for the string literal in the diagnostic.
std::optional<StringRef>
getStringLiteralIfNotInterpolated(SourceLoc Loc, StringRef DiagText);
/// Returns true to indicate that experimental concurrency syntax should be
/// parsed if the parser is generating only a syntax tree or if the user has
/// passed the `-enable-experimental-concurrency` flag to the frontend.
bool shouldParseExperimentalConcurrency() const {
return Context.LangOpts.EnableExperimentalConcurrency;
}
public:
InFlightDiagnostic diagnose(SourceLoc Loc, DiagRef Diag) {
if (Diags.isDiagnosticPointsToFirstBadToken(Diag.getID()) &&
Loc == Tok.getLoc() && Tok.isAtStartOfLine())
Loc = getEndOfPreviousLoc();
return Diags.diagnose(Loc, Diag);
}
InFlightDiagnostic diagnose(Token Tok, DiagRef Diag) {
return diagnose(Tok.getLoc(), Diag);
}
template<typename ...DiagArgTypes, typename ...ArgTypes>
InFlightDiagnostic diagnose(SourceLoc Loc, Diag<DiagArgTypes...> DiagID,
ArgTypes &&...Args) {
return diagnose(Loc, {DiagID, {std::forward<ArgTypes>(Args)...}});
}
template<typename ...DiagArgTypes, typename ...ArgTypes>
InFlightDiagnostic diagnose(Token Tok, Diag<DiagArgTypes...> DiagID,
ArgTypes &&...Args) {
return diagnose(Tok.getLoc(),
{DiagID, {std::forward<ArgTypes>(Args)...}});
}
/// Add a fix-it to remove the space in consecutive identifiers.
/// Add a camel-cased option if it is different than the first option.
void diagnoseConsecutiveIDs(StringRef First, SourceLoc FirstLoc,
StringRef DeclKindName);
bool startsWithSymbol(Token Tok, char symbol) {
return (Tok.isAnyOperator() || Tok.isPunctuation()) &&
Tok.getText()[0] == symbol;
}
/// Check whether the current token starts with '<'.
bool startsWithLess(Token Tok) { return startsWithSymbol(Tok, '<'); }
/// Check whether the current token starts with '>'.
bool startsWithGreater(Token Tok) { return startsWithSymbol(Tok, '>'); }
/// Check whether the current token starts with '...'.
bool startsWithEllipsis(Token Tok);
/// Check whether the current token starts with a multi-line string delimiter.
bool startsWithMultilineStringDelimiter(Token Tok) {
return Tok.getText().ltrim('#').starts_with("\"\"\"");
}
/// Returns true if token is an identifier with the given value.
bool isIdentifier(Token Tok, StringRef value) {
return Tok.is(tok::identifier) && Tok.getText() == value;
}
/// Consume the starting '<' of the current token, which may either
/// be a complete '<' token or some kind of operator token starting with '<',
/// e.g., '<>'.
SourceLoc consumeStartingLess();
/// Consume the starting '>' of the current token, which may either
/// be a complete '>' token or some kind of operator token starting with '>',
/// e.g., '>>'.
SourceLoc consumeStartingGreater();
/// Consume the starting '...' of the current token, which may either be a
/// complete '...' token or some kind of operator token starting with '...',
/// e.g '...>'.
SourceLoc consumeStartingEllipsis();
/// Consume the starting character of the current token, and split the
/// remainder of the token into a new token (or tokens).
SourceLoc
consumeStartingCharacterOfCurrentToken(tok Kind = tok::oper_binary_unspaced,
size_t Len = 1);
//===--------------------------------------------------------------------===//
// Primitive Parsing
/// Consume an identifier (but not an operator) if present and return
/// its name in \p Result. Otherwise, emit an error.
///
/// \returns false on success, true on error.
bool parseIdentifier(Identifier &Result, SourceLoc &Loc, DiagRef D,
bool diagnoseDollarPrefix);
/// Consume an identifier with a specific expected name. This is useful for
/// contextually sensitive keywords that must always be present.
bool parseSpecificIdentifier(StringRef expected, SourceLoc &Loc,
DiagRef D);
template<typename ...DiagArgTypes, typename ...ArgTypes>
bool parseIdentifier(Identifier &Result, SourceLoc &L,
bool diagnoseDollarPrefix, Diag<DiagArgTypes...> ID,
ArgTypes... Args) {
return parseIdentifier(Result, L, {ID, {Args...}},
diagnoseDollarPrefix);
}
template<typename ...DiagArgTypes, typename ...ArgTypes>
bool parseSpecificIdentifier(StringRef expected,
Diag<DiagArgTypes...> ID, ArgTypes... Args) {
SourceLoc L;
return parseSpecificIdentifier(expected, L, {ID, {Args...}});
}
/// Consume an identifier or operator if present and return its name
/// in \p Result. Otherwise, emit an error and return true.
bool parseAnyIdentifier(Identifier &Result, SourceLoc &Loc,
DiagRef D, bool diagnoseDollarPrefix);
template<typename ...DiagArgTypes, typename ...ArgTypes>
bool parseAnyIdentifier(Identifier &Result, bool diagnoseDollarPrefix,
Diag<DiagArgTypes...> ID, ArgTypes... Args) {
SourceLoc L;
return parseAnyIdentifier(Result, L, {ID, {Args...}},
diagnoseDollarPrefix);
}
/// \brief Parse an unsigned integer and returns it in \p Result. On failure
/// emit the specified error diagnostic, and a note at the specified note
/// location.
bool parseUnsignedInteger(unsigned &Result, SourceLoc &Loc,
DiagRef D);
/// The parser expects that \p K is next token in the input. If so,
/// it is consumed and false is returned.
///
/// If the input is malformed, this emits the specified error diagnostic.
bool parseToken(tok K, SourceLoc &TokLoc, DiagRef D);
template<typename ...DiagArgTypes, typename ...ArgTypes>
bool parseToken(tok K, Diag<DiagArgTypes...> ID, ArgTypes... Args) {
SourceLoc L;
return parseToken(K, L, {ID, {Args...}});
}
template<typename ...DiagArgTypes, typename ...ArgTypes>
bool parseToken(tok K, SourceLoc &L,
Diag<DiagArgTypes...> ID, ArgTypes... Args) {
return parseToken(K, L, {ID, {Args...}});
}
/// Parse the specified expected token and return its location on success. On failure, emit the specified
/// error diagnostic, a note at the specified note location, and return the location of the previous token.
bool parseMatchingToken(tok K, SourceLoc &TokLoc, DiagRef ErrorDiag,
SourceLoc OtherLoc);
/// Returns the proper location for a missing right brace, parenthesis, etc.
SourceLoc getLocForMissingMatchingToken() const;
/// When encountering an error or a missing matching token (e.g. '}'), return
/// the location to use for it. This value should be at the last token in
/// the ASTNode being parsed so that it nests within any enclosing nodes, and,
/// for ASTScope lookups, it does not precede any identifiers to be looked up.
/// However, the latter case does not hold when parsing an interpolated
/// string literal because there may be identifiers to be looked up in the
/// literal and their locations will not precede the location of a missing
/// close brace.
SourceLoc getErrorOrMissingLoc() const;
enum class ParseListItemResult {
/// There are more list items to parse.
Continue,
/// The list ended inside a string literal interpolation context.
FinishedInStringInterpolation,
/// The list ended for another reason.
Finished,
};
/// Parses a single item from a comma separated list and updates `Status`.
ParseListItemResult
parseListItem(ParserStatus &Status, tok RightK, SourceLoc LeftLoc,
SourceLoc &RightLoc, bool AllowSepAfterLast,
llvm::function_ref<ParserStatus()> callback);
/// Parse a comma separated list of some elements.
ParserStatus parseList(tok RightK, SourceLoc LeftLoc, SourceLoc &RightLoc,
bool AllowSepAfterLast, DiagRef RightErrorDiag,
llvm::function_ref<ParserStatus()> callback);
void consumeTopLevelDecl(ParserPosition BeginParserPosition,
TopLevelCodeDecl *TLCD);
ParserStatus parseBraceItems(SmallVectorImpl<ASTNode> &Decls,
BraceItemListKind Kind,
BraceItemListKind ConditionalBlockKind,
bool &IsFollowingGuard);
ParserStatus parseBraceItems(SmallVectorImpl<ASTNode> &Decls,
BraceItemListKind Kind =
BraceItemListKind::Brace,
BraceItemListKind ConditionalBlockKind =
BraceItemListKind::Brace) {
bool IsFollowingGuard = false;
return parseBraceItems(Decls, Kind, ConditionalBlockKind,
IsFollowingGuard);
}
ParserResult<BraceStmt> parseBraceItemList(Diag<> ID);
//===--------------------------------------------------------------------===//
// Decl Parsing
/// Returns true if parser is at the start of a Swift decl or decl-import.
bool isStartOfSwiftDecl(bool allowPoundIfAttributes = true,
bool hadAttrsOrModifiers = false);
/// Returns true if the parser is at the start of a SIL decl.
bool isStartOfSILDecl();
/// Returns true if the parser is at a freestanding macro expansion.
bool isStartOfFreestandingMacroExpansion();
/// Parse the top-level Swift items into the provided vector.
///
/// Each item will be a declaration, statement, or expression.
void parseTopLevelItems(SmallVectorImpl<ASTNode> &items);
/// Parse the source file via the Swift Parser using the ASTGen library.
void
parseSourceFileViaASTGen(SmallVectorImpl<ASTNode> &items,
std::optional<DiagnosticTransaction> &transaction,
bool suppressDiagnostics = false);
/// Parse the top-level SIL decls into the SIL module.
/// \returns \c true if there was a parsing error.
bool parseTopLevelSIL();
bool isStartOfGetSetAccessor();
/// Flags that control the parsing of declarations.
enum ParseDeclFlags {
PD_Default = 0,
PD_AllowTopLevel = 1 << 1,
PD_HasContainerType = 1 << 2,
PD_DisallowInit = 1 << 3,
PD_AllowEnumElement = 1 << 4,
PD_InProtocol = 1 << 5,
PD_InClass = 1 << 6,
PD_InExtension = 1 << 7,
PD_InStruct = 1 << 8,
PD_InEnum = 1 << 9,
};
/// Options that control the parsing of declarations.
using ParseDeclOptions = OptionSet<ParseDeclFlags>;
void consumeDecl(ParserPosition BeginParserPosition, bool IsTopLevel);
ParserStatus parseDecl(bool IsAtStartOfLineOrPreviousHadSemi,
bool IfConfigsAreDeclAttrs,
llvm::function_ref<void(Decl *)> Handler,
bool fromASTGen = false);
std::pair<std::vector<Decl *>, std::optional<Fingerprint>>
parseDeclListDelayed(IterableDeclContext *IDC);
bool parseMemberDeclList(SourceLoc &LBLoc, SourceLoc &RBLoc,
Diag<> LBraceDiag, Diag<> RBraceDiag,
IterableDeclContext *IDC);
bool canDelayMemberDeclParsing(bool &HasOperatorDeclarations,
bool &HasNestedClassDeclarations);
bool canDelayFunctionBodyParsing(bool &HasNestedTypeDeclarations);
bool delayParsingDeclList(SourceLoc LBLoc, SourceLoc &RBLoc,
IterableDeclContext *IDC);
ParserResult<TypeDecl> parseDeclTypeAlias(ParseDeclOptions Flags,
DeclAttributes &Attributes);
ParserResult<TypeDecl> parseDeclAssociatedType(ParseDeclOptions Flags,
DeclAttributes &Attributes);
/// Parse a #if ... #endif directive.
/// Delegate callback function to parse elements in the blocks and record
/// them however they wish. The parsing function will be provided with the
/// location of the clause token (`#if`, `#else`, etc.), the condition,
/// whether this is the active clause, and the role of the elements.
template <typename Result>
Result parseIfConfigRaw(
IfConfigContext ifConfigContext,
llvm::function_ref<void(SourceLoc clauseLoc, Expr *condition,
bool isActive, IfConfigElementsRole role)>
parseElements,
llvm::function_ref<Result(SourceLoc endLoc, bool hadMissingEnd)> finish);
/// Parse a #if ... #endif directive.
/// Delegate callback function to parse elements in the blocks.
ParserStatus parseIfConfig(
IfConfigContext ifConfigContext,
llvm::function_ref<void(bool)> parseElements);
/// Parse an #if ... #endif containing only attributes.
ParserStatus parseIfConfigDeclAttributes(
DeclAttributes &attributes, bool ifConfigsAreDeclAttrs,
PatternBindingInitializer *initContext);
/// Parse a #error or #warning diagnostic.
ParserResult<PoundDiagnosticDecl> parseDeclPoundDiagnostic();
/// Parse a #line/#sourceLocation directive.
/// 'isLine = true' indicates parsing #line instead of #sourcelocation
ParserStatus parseLineDirective(bool isLine = false);
/// Skip an `#if` configuration block containing only attributes.
///
/// \returns true if the skipping was successful, false otherwise.
bool skipIfConfigOfAttributes(bool &sawAnyAttributes);
/// Determine whether the `#if` at which the parser occurs only contains
/// attributes (in all branches), in which case it is treated as part of
/// an attribute list.
bool ifConfigContainsOnlyAttributes();
/// Parse the optional attributes before a declaration.
ParserStatus parseDeclAttributeList(DeclAttributes &Attributes,
bool IfConfigsAreDeclAttrs = false);
/// Parse the optional attributes before a declaration.
///
/// This is the inner loop, which can be called recursively.
ParserStatus parseDeclAttributeList(DeclAttributes &Attributes,
bool IfConfigsAreDeclAttrs,
PatternBindingInitializer *initContext);
/// Parse the optional attributes before a closure declaration.
ParserStatus parseClosureDeclAttributeList(DeclAttributes &Attributes);
/// Parse the optional modifiers before a declaration.
ParserStatus parseDeclModifierList(DeclAttributes &Attributes,
SourceLoc &StaticLoc,
StaticSpellingKind &StaticSpelling,
bool isFromClangAttribute = false);
/// Parse an availability attribute of the form
/// @available(*, introduced: 1.0, deprecated: 3.1).
/// \return \p nullptr if the platform name is invalid
ParserResult<AvailableAttr>
parseExtendedAvailabilitySpecList(SourceLoc AtLoc, SourceLoc AttrLoc,
StringRef AttrName);
/// Parse a string literal whose contents can be interpreted as a UUID.
///
/// \returns false on success, true on error.
bool parseUUIDString(UUID &uuid, Diag<> diag, bool justChecking = false);
/// Parse the Objective-C selector inside @objc
void parseObjCSelector(SmallVector<Identifier, 4> &Names,
SmallVector<SourceLoc, 4> &NameLocs,
bool &IsNullarySelector);
/// Parse a parenthesized and comma-separated list of attribute arguments.
///
/// \returns false on success, true on error.
ParserStatus
parseAttributeArguments(SourceLoc attrLoc, StringRef attrName,
bool isAttrModifier, SourceRange &parensRange,
llvm::function_ref<ParserStatus()> parseAttr);
/// Parse the @_specialize attribute.
/// \p closingBrace is the expected closing brace, which can be either ) or ]
/// \p Attr is where to store the parsed attribute
bool parseSpecializeAttribute(
swift::tok ClosingBrace, SourceLoc AtLoc, SourceLoc Loc,
SpecializeAttr *&Attr, AvailabilityRange *SILAvailability,
llvm::function_ref<bool(Parser &)> parseSILTargetName =
[](Parser &) { return false; },
llvm::function_ref<bool(Parser &)> parseSILSIPModule =
[](Parser &) { return false; });
/// Parse the arguments inside the @_specialize attribute
bool parseSpecializeAttributeArguments(
swift::tok ClosingBrace, bool &DiscardAttribute,
std::optional<bool> &Exported,
std::optional<SpecializeAttr::SpecializationKind> &Kind,
TrailingWhereClause *&TrailingWhereClause, DeclNameRef &targetFunction,
AvailabilityRange *SILAvailability,
SmallVectorImpl<Identifier> &spiGroups,
SmallVectorImpl<AvailableAttr *> &availableAttrs,
size_t &typeErasedParamsCount,
llvm::function_ref<bool(Parser &)> parseSILTargetName,
llvm::function_ref<bool(Parser &)> parseSILSIPModule);
/// Parse the @storageRestrictions(initializes:accesses:) attribute.
/// \p Attr is where to store the parsed attribute
ParserResult<StorageRestrictionsAttr>
parseStorageRestrictionsAttribute(SourceLoc AtLoc, SourceLoc Loc);
/// Parse the @_implements attribute.
/// \p Attr is where to store the parsed attribute
ParserResult<ImplementsAttr> parseImplementsAttribute(SourceLoc AtLoc,
SourceLoc Loc);
/// Parse the @differentiable attribute.
ParserResult<DifferentiableAttr> parseDifferentiableAttribute(SourceLoc AtLoc,
SourceLoc Loc);
/// Parse the @_extern attribute.
bool parseExternAttribute(DeclAttributes &Attributes, bool &DiscardAttribute,
StringRef AttrName, SourceLoc AtLoc, SourceLoc Loc);
/// Parse the arguments inside the @differentiable attribute.
bool parseDifferentiableAttributeArguments(
DifferentiabilityKind &diffKind,
SmallVectorImpl<ParsedAutoDiffParameter> &params,
TrailingWhereClause *&whereClause);
/// Parse a differentiability parameters clause, i.e. the 'wrt:' clause in
/// `@differentiable`, `@derivative`, and `@transpose` attributes.
///
/// If `allowNamedParameters` is false, allow only index parameters and
/// 'self'. Used for `@transpose` attributes.
bool parseDifferentiabilityParametersClause(
SmallVectorImpl<ParsedAutoDiffParameter> &parameters, StringRef attrName,
bool allowNamedParameters = true);
/// Parse the @derivative attribute.
ParserResult<DerivativeAttr> parseDerivativeAttribute(SourceLoc AtLoc,
SourceLoc Loc);
/// Parse the @transpose attribute.
ParserResult<TransposeAttr> parseTransposeAttribute(SourceLoc AtLoc,
SourceLoc Loc);
/// Parse the @backDeployed attribute.
bool parseBackDeployedAttribute(DeclAttributes &Attributes,
StringRef AttrName, SourceLoc AtLoc,
SourceLoc Loc);
/// Parse the @_documentation attribute.
ParserResult<DocumentationAttr> parseDocumentationAttribute(SourceLoc AtLoc,
SourceLoc Loc);
/// Parse a single argument from a @_documentation attribute.
bool
parseDocumentationAttributeArgument(std::optional<StringRef> &Metadata,
std::optional<AccessLevel> &Visibility);
ParserResult<AllowFeatureSuppressionAttr>
parseAllowFeatureSuppressionAttribute(bool inverted, SourceLoc atLoc,
SourceLoc loc);
/// Parse the @attached or @freestanding attribute that specifies a macro
/// role.
ParserResult<MacroRoleAttr> parseMacroRoleAttribute(
MacroSyntax syntax, SourceLoc AtLoc, SourceLoc Loc
);
/// Parse the @lifetime attribute.
ParserResult<LifetimeAttr> parseLifetimeAttribute(SourceLoc AtLoc,
SourceLoc Loc);
/// Parse a specific attribute.
ParserStatus parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
SourceLoc AtEndLoc,
PatternBindingInitializer *&initContext,
bool isFromClangAttribute = false);
bool isCustomAttributeArgument();
bool canParseCustomAttribute();
/// Parse a custom attribute after the initial '@'.
///
/// \param atLoc The location of the already-parsed '@'.
///
/// \param initContext A reference to the initializer context used
/// for the set of custom attributes. This should start as nullptr, and
/// will get filled in by this function. The same variable should be provided
/// for every custom attribute within the same attribute list.
ParserResult<CustomAttr> parseCustomAttribute(
SourceLoc atLoc, PatternBindingInitializer *&initContext);
ParserStatus parseNewDeclAttribute(DeclAttributes &Attributes,
SourceLoc AtLoc, DeclAttrKind DK,
bool isFromClangAttribute = false);
/// Parse a version tuple of the form x[.y[.z]]. Returns true if there was
/// an error parsing.
bool parseVersionTuple(llvm::VersionTuple &Version, SourceRange &Range,
DiagRef D);
bool isParameterSpecifier() {
if (Tok.is(tok::kw_inout)) return true;
if (!canHaveParameterSpecifierContextualKeyword()) return false;
if (Tok.isContextualKeyword("__shared") ||
Tok.isContextualKeyword("__owned") ||
Tok.isContextualKeyword("borrowing") ||
Tok.isContextualKeyword("consuming") ||
Tok.isContextualKeyword("isolated") ||
Tok.isContextualKeyword("_const"))
return true;
if (Context.LangOpts.hasFeature(Feature::SendingArgsAndResults) &&
Tok.isContextualKeyword("sending"))
return true;
if (Context.LangOpts.hasFeature(Feature::NonescapableTypes) &&
isLifetimeDependenceToken())
return true;
return false;
}
/// Given that we just returned true from isParameterSpecifier(), skip
/// over the specifier.
void skipParameterSpecifier() {
// These are all currently single tokens.
consumeToken();
}
bool isLifetimeDependenceToken() {
if (!isInSILMode()) {
return Tok.isContextualKeyword("dependsOn");
}
return Tok.isContextualKeyword("_inherit") ||
Tok.isContextualKeyword("_scope");
}
bool canHaveParameterSpecifierContextualKeyword() {
// The parameter specifiers like `isolated`, `consuming`, `borrowing` are
// also valid identifiers and could be the name of a type. Check whether
// the following token is something that can introduce a type. Thankfully
// none of these tokens overlap with the set of tokens that can follow an
// identifier in a type production.
if (Tok.is(tok::identifier)) {
auto next = peekToken();
if (next.isAny(tok::at_sign, tok::kw_inout, tok::l_paren,
tok::identifier, tok::l_square, tok::kw_Any,
tok::kw_Self, tok::kw__, tok::kw_var,
tok::kw_let, tok::code_complete))
return true;
if (next.is(tok::oper_prefix) && next.getText() == "~")
return true;
}
return isLifetimeDependenceToken();
}
bool parseConventionAttributeInternal(SourceLoc atLoc, SourceLoc attrLoc,
ConventionTypeAttr *&result,
bool justChecking);
ParserStatus
parseLifetimeEntries(SmallVectorImpl<LifetimeEntry> &specifierList);
ParserResult<ImportDecl> parseDeclImport(ParseDeclOptions Flags,
DeclAttributes &Attributes);
/// Parse an inheritance clause into a vector of InheritedEntry's.
///
/// \param allowClassRequirement whether to permit parsing of 'class'
/// \param allowAnyObject whether to permit parsing of 'AnyObject'
ParserStatus parseInheritance(SmallVectorImpl<InheritedEntry> &Inherited,
bool allowClassRequirement,
bool allowAnyObject);
ParserStatus parseDeclItem(bool &PreviousHadSemi,
llvm::function_ref<void(Decl *)> handler);
std::pair<std::vector<Decl *>, std::optional<Fingerprint>>
parseDeclList(SourceLoc LBLoc, SourceLoc &RBLoc, Diag<> ErrorDiag,
bool &hadError);
ParserResult<ExtensionDecl> parseDeclExtension(ParseDeclOptions Flags,
DeclAttributes &Attributes);
ParserResult<EnumDecl> parseDeclEnum(ParseDeclOptions Flags,
DeclAttributes &Attributes);
ParserResult<EnumCaseDecl>
parseDeclEnumCase(ParseDeclOptions Flags, DeclAttributes &Attributes,
SmallVectorImpl<Decl *> &decls);
ParserResult<StructDecl>
parseDeclStruct(ParseDeclOptions Flags, DeclAttributes &Attributes);
ParserResult<ClassDecl>
parseDeclClass(ParseDeclOptions Flags, DeclAttributes &Attributes);
ParserResult<PatternBindingDecl>
parseDeclVar(ParseDeclOptions Flags, DeclAttributes &Attributes,
SmallVectorImpl<Decl *> &Decls,
SourceLoc StaticLoc,
StaticSpellingKind StaticSpelling,
SourceLoc TryLoc,
bool HasLetOrVarKeyword = true);
struct ParsedAccessors;
bool parseAccessorAfterIntroducer(
SourceLoc Loc, AccessorKind Kind, ParsedAccessors &accessors,
bool &hasEffectfulGet, bool &parsingLimitedSyntax,
DeclAttributes &Attributes, ParseDeclOptions Flags,
AbstractStorageDecl *storage, ParserStatus &Status);
ParserStatus parseGetSet(ParseDeclOptions Flags, ParameterList *Indices,
TypeRepr *ResultType, ParsedAccessors &accessors,
AbstractStorageDecl *storage);
ParserResult<VarDecl> parseDeclVarGetSet(PatternBindingEntry &entry,
ParseDeclOptions Flags,
SourceLoc StaticLoc,
StaticSpellingKind StaticSpelling,
SourceLoc VarLoc,
bool hasInitializer,
const DeclAttributes &Attributes,
SmallVectorImpl<Decl *> &Decls);
ParserStatus parseGetEffectSpecifier(ParsedAccessors &accessors,
SourceLoc &asyncLoc,
SourceLoc &throwsLoc,
TypeRepr *&thrownTy,
bool &hasEffectfulGet,
AccessorKind currentKind,
SourceLoc const& currentLoc);
/// Parse accessors provided as a separate list, for use in macro
/// expansions.
void parseTopLevelAccessors(
AbstractStorageDecl *storage, SmallVectorImpl<ASTNode> &items
);
/// Parse the result of attribute macro expansion, which is a floating
/// attribute list.
///
/// Parsing a floating attribute list will produce a `MissingDecl` with
/// the attribute list attached.
void parseExpandedAttributeList(SmallVectorImpl<ASTNode> &items);
/// Parse the result of member macro expansion, which is a floating
/// member list.
void parseExpandedMemberList(SmallVectorImpl<ASTNode> &items);
ParserResult<FuncDecl> parseDeclFunc(SourceLoc StaticLoc,
StaticSpellingKind StaticSpelling,
ParseDeclOptions Flags,
DeclAttributes &Attributes,
bool HasFuncKeyword = true);
BodyAndFingerprint
parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD);
void parseAbstractFunctionBody(AbstractFunctionDecl *AFD);
BodyAndFingerprint
parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD);
ParserResult<MacroDecl> parseDeclMacro(DeclAttributes &Attributes);
ParserStatus parsePrimaryAssociatedTypes(
SmallVectorImpl<PrimaryAssociatedTypeName> &AssocTypeNames);
ParserStatus parsePrimaryAssociatedTypeList(
SmallVectorImpl<PrimaryAssociatedTypeName> &AssocTypeNames);
ParserResult<ProtocolDecl> parseDeclProtocol(ParseDeclOptions Flags,
DeclAttributes &Attributes);
ParserResult<SubscriptDecl>
parseDeclSubscript(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
ParseDeclOptions Flags, DeclAttributes &Attributes,
SmallVectorImpl<Decl *> &Decls);
ParserResult<ConstructorDecl>
parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes);
ParserResult<DestructorDecl>
parseDeclDeinit(ParseDeclOptions Flags, DeclAttributes &Attributes);
ParserResult<OperatorDecl> parseDeclOperator(ParseDeclOptions Flags,
DeclAttributes &Attributes);
ParserResult<OperatorDecl> parseDeclOperatorImpl(SourceLoc OperatorLoc,
Identifier Name,
SourceLoc NameLoc,
DeclAttributes &Attrs);
ParserResult<PrecedenceGroupDecl>
parseDeclPrecedenceGroup(ParseDeclOptions flags, DeclAttributes &attributes);
ParserResult<MacroExpansionDecl>
parseDeclMacroExpansion(ParseDeclOptions flags, DeclAttributes &attributes);
ParserResult<TypeRepr> parseDeclResultType(Diag<> MessageID);
/// Get the location for a type error.
SourceLoc getTypeErrorLoc() const;
//===--------------------------------------------------------------------===//
// Type Parsing
enum class ParseTypeReason {
/// Any type parsing context.
Unspecified,
/// Whether the type is for a closure attribute.
CustomAttribute,
/// A type in an inheritance clause.
InheritanceClause,
};
ParserResult<TypeRepr> parseTypeScalar(
Diag<> MessageID,
ParseTypeReason reason);
ParserResult<TypeRepr> parseType();
ParserResult<TypeRepr>
parseType(Diag<> MessageID,
ParseTypeReason reason = ParseTypeReason::Unspecified,
bool fromASTGen = false);
/// Parse a type optionally prefixed by a list of named opaque parameters. If
/// no params present, return 'type'. Otherwise, return 'type-named-opaque'.
///
/// type-named-opaque:
/// generic-params type
ParserResult<TypeRepr> parseTypeWithOpaqueParams(Diag<> MessageID);
ParserResult<TypeRepr>
parseTypeSimpleOrComposition(Diag<> MessageID, ParseTypeReason reason);
ParserResult<TypeRepr> parseTypeSimple(
Diag<> MessageID, ParseTypeReason reason);
/// Parse layout constraint.
LayoutConstraint parseLayoutConstraint(Identifier LayoutConstraintID);
ParserStatus parseGenericArguments(SmallVectorImpl<TypeRepr *> &Args,
SourceLoc &LAngleLoc,
SourceLoc &RAngleLoc);
/// Parses and returns the base type for a qualified declaration name,
/// positioning the parser at the '.' before the final declaration name. This
/// position is important for parsing final declaration names like '.init' via
/// `parseUnqualifiedDeclName`. For example, 'Foo.Bar.f' parses as 'Foo.Bar'
/// and the parser is positioned at '.f'. If there is no base type qualifier
/// (e.g. when parsing just 'f'), returns an empty parser error.
///
/// \verbatim
/// qualified-decl-name-base-type:
/// identifier generic-args? ('.' identifier generic-args?)*
/// \endverbatim
ParserResult<TypeRepr> parseQualifiedDeclNameBaseType();
/// Parse a single type identifier, possibly followed by a generic argument
/// list, e.g `Foo` or `Bar<Int>`.
///
/// \verbatim
/// type-identifier: identifier generic-args?
/// \endverbatim
ParserResult<DeclRefTypeRepr> parseTypeIdentifier(TypeRepr *Base);
/// Parse a dotted type, e.g. 'Foo<X>.Y.Z', 'P.Type', '[X].Y'.
ParserResult<TypeRepr> parseTypeDotted(ParserResult<TypeRepr> Base);
struct ParsedTypeAttributeList {
ParseTypeReason ParseReason;
ParamDecl::Specifier Specifier = ParamDecl::Specifier::Default;
SourceLoc SpecifierLoc;
SourceLoc IsolatedLoc;
SourceLoc ConstLoc;
SourceLoc SendingLoc;
SmallVector<TypeOrCustomAttr> Attributes;
SmallVector<LifetimeEntry> lifetimeEntries;
ParsedTypeAttributeList(ParseTypeReason reason) : ParseReason(reason) {}
/// Main entry point for parsing.
///
/// Inline we just have the fast path of failing to match. We call slowParse
/// that contains the outline of more complex implementation. This is HOT
/// code!
ParserStatus parse(Parser &P) {
auto &Tok = P.Tok;
if (Tok.is(tok::at_sign) || P.isParameterSpecifier())
return slowParse(P);
return makeParserSuccess();
}
TypeRepr *applyAttributesToType(Parser &P, TypeRepr *Type) const;
private:
/// An out of line implementation of the more complicated cases. This
/// ensures on the inlined fast path we handle the case of not matching.
ParserStatus slowParse(Parser &P);
};
ParserStatus parseTypeAttribute(TypeOrCustomAttr &result, SourceLoc AtLoc,
SourceLoc AtEndLoc, ParseTypeReason reason,
PatternBindingInitializer *&initContext,
bool justChecking = false);
ParserResult<TypeRepr> parseOldStyleProtocolComposition();
ParserResult<TypeRepr> parseAnyType();
ParserResult<TypeRepr> parseSILBoxType(GenericParamList *generics,
ParsedTypeAttributeList &attrs);
ParserResult<TypeRepr> parseTypeTupleBody();
ParserResult<TypeRepr> parseTypeArray(ParserResult<TypeRepr> Base);
/// Parse a collection type.
/// type-simple:
/// '[' type ']'
/// '[' type ':' type ']'
ParserResult<TypeRepr> parseTypeCollection();
ParserResult<TypeRepr> parseTypeOptional(ParserResult<TypeRepr> Base);
ParserResult<TypeRepr>
parseTypeImplicitlyUnwrappedOptional(ParserResult<TypeRepr> Base);
bool isOptionalToken(const Token &T) const;
SourceLoc consumeOptionalToken();
bool isImplicitlyUnwrappedOptionalToken(const Token &T) const;
SourceLoc consumeImplicitlyUnwrappedOptionalToken();
//===--------------------------------------------------------------------===//
// Pattern Parsing
/// A structure for collecting information about the default
/// arguments of a context.
struct DefaultArgumentInfo {
llvm::SmallVector<DefaultArgumentInitializer *, 4> ParsedContexts;
unsigned NextIndex : 31;
/// Track whether or not one of the parameters in a signature's argument
/// list accepts a default argument.
unsigned HasDefaultArgument : 1;
/// Claim the next argument index. It's important to do this for
/// all the arguments, not just those that have default arguments.
unsigned claimNextIndex() { return NextIndex++; }
/// Set the parsed context of all default argument initializers to
/// the given function, enum case or subscript.
void setFunctionContext(DeclContext *DC, ParameterList *paramList);
DefaultArgumentInfo() {
NextIndex = 0;
HasDefaultArgument = false;
}
};
/// Describes a parsed parameter.
struct ParsedParameter {
/// Any declaration attributes attached to the parameter.
DeclAttributes Attrs;
/// The location of the 'inout' keyword, if present.
SourceLoc SpecifierLoc;
/// The parsed specifier kind, if present.
ParamDecl::Specifier SpecifierKind = ParamDecl::Specifier::Default;
/// The location of the first name.
///
/// \c FirstName is the name.
SourceLoc FirstNameLoc;
/// The location of the second name, if present.
///
/// \p SecondName is the name.
SourceLoc SecondNameLoc;
/// The first name.
Identifier FirstName;
/// The second name, the presence of which is indicated by \c SecondNameLoc.
Identifier SecondName;
/// The location of the 'isolated' keyword, if present.
SourceLoc IsolatedLoc;
/// The location of the '_const' keyword, if present.
SourceLoc CompileConstLoc;
/// The location of the 'sending' keyword if present.
SourceLoc SendingLoc;
/// The type following the ':'.
TypeRepr *Type = nullptr;
/// The default argument for this parameter.
Expr *DefaultArg = nullptr;
/// True if we emitted a parse error about this parameter.
bool isInvalid = false;
/// True if this parameter is potentially destructuring a tuple argument.
bool isPotentiallyDestructured = false;
};
/// Describes the context in which the given parameter is being parsed.
enum class ParameterContextKind {
/// An operator.
Operator,
/// A function.
Function,
/// An initializer.
Initializer,
/// A closure.
Closure,
/// A subscript.
Subscript,
/// A curried argument clause.
Curried,
/// An enum element.
EnumElement,
/// A macro.
Macro,
};
/// Whether we are at the start of a parameter name when parsing a parameter.
bool startsParameterName(bool isClosure);
/// Attempts to perform code completion for the possible start of a function
/// parameter type, returning the source location of the consumed completion
/// token, or a null location if there is no completion token.
SourceLoc tryCompleteFunctionParamTypeBeginning();
/// Parse a parameter-clause.
///
/// \verbatim
/// parameter-clause:
/// '(' ')'
/// '(' parameter (',' parameter)* '...'? )'
///
/// parameter:
/// 'inout'? ('let' | 'var')? '`'? identifier-or-none identifier-or-none?
/// (':' type)? ('...' | '=' expr)?
///
/// identifier-or-none:
/// identifier
/// '_'
/// \endverbatim
ParserStatus parseParameterClause(SourceLoc &leftParenLoc,
SmallVectorImpl<ParsedParameter> &params,
SourceLoc &rightParenLoc,
DefaultArgumentInfo *defaultArgs,
ParameterContextKind paramContext);
ParserResult<ParameterList> parseSingleParameterClause(
ParameterContextKind paramContext,
SmallVectorImpl<Identifier> *namePieces = nullptr,
DefaultArgumentInfo *defaultArgs = nullptr);
ParserStatus parseFunctionArguments(SmallVectorImpl<Identifier> &NamePieces,
ParameterList *&BodyParams,
ParameterContextKind paramContext,
DefaultArgumentInfo &defaultArgs);
ParserStatus parseFunctionSignature(DeclBaseName functionName,
DeclName &fullName,
ParameterList *&bodyParams,
DefaultArgumentInfo &defaultArgs,
SourceLoc &asyncLoc,
bool &reasync,
SourceLoc &throws,
bool &rethrows,
TypeRepr *&thrownType,
TypeRepr *&retType);
/// Parse 'async' and 'throws', if present, putting the locations of the
/// keywords into the \c SourceLoc parameters.
///
/// \param existingArrowLoc The location of an existing '->', if there is
/// one. Parsing 'async' or 'throws' after the `->` is an error we
/// correct for.
///
/// \param reasync If non-NULL, will also parse the 'reasync' keyword in
/// lieu of 'async'.
///
/// \param rethrows If non-NULL, will also parse the 'rethrows' keyword in
/// lieu of 'throws'.
ParserStatus parseEffectsSpecifiers(SourceLoc existingArrowLoc,
SourceLoc &asyncLoc, bool *reasync,
SourceLoc &throwsLoc, bool *rethrows,
TypeRepr *&thrownType);
/// Returns 'true' if \p T is consider a throwing effect specifier.
static bool isThrowsEffectSpecifier(const Token &T);
/// Returns 'true' if \p T is considered effects specifier.
static bool isEffectsSpecifier(const Token &T);
//===--------------------------------------------------------------------===//
// Pattern Parsing
ParserResult<Pattern> parseTypedPattern();
ParserResult<Pattern> parsePattern();
/// Parse a tuple pattern element.
///
/// \code
/// pattern-tuple-element:
/// pattern ('=' expr)?
/// \endcode
///
/// \returns The tuple pattern element, if successful.
std::pair<ParserStatus, std::optional<TuplePatternElt>>
parsePatternTupleElement();
ParserResult<Pattern> parsePatternTuple();
ParserResult<Pattern>
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> P);
ParserResult<Pattern> parseMatchingPattern(bool isExprBasic);
ParserResult<Pattern>
parseMatchingPatternAsBinding(PatternBindingState newState, SourceLoc VarLoc,
bool isExprBasic);
Pattern *createBindingFromPattern(SourceLoc loc, Identifier name,
VarDecl::Introducer introducer);
/// Determine whether this token can only start a matching pattern
/// production and not an expression.
bool isOnlyStartOfMatchingPattern();
//===--------------------------------------------------------------------===//
// Speculative type list parsing
//===--------------------------------------------------------------------===//
/// Returns true if we can parse a generic argument list at the current
/// location in expression context. This parses types without generating
/// AST nodes from the '<' at the current location up to a matching '>'. If
/// the type list parse succeeds, and the closing '>' is followed by one
/// of the following tokens:
/// lparen_following rparen lsquare_following rsquare lbrace rbrace
/// period_following comma semicolon
/// then this function returns true, and the expression will parse as a
/// generic parameter list. If the parse fails, or the closing '>' is not
/// followed by one of the above tokens, then this function returns false,
/// and the expression will parse with the '<' as an operator.
bool canParseAsGenericArgumentList();
bool canParseType();
/// Returns true if a simple type identifier can be parsed.
///
/// \verbatim
/// simple-type-identifier: identifier generic-argument-list?
/// \endverbatim
bool canParseTypeIdentifier();
bool canParseOldStyleProtocolComposition();
bool canParseTypeTupleBody();
bool canParseTypeAttribute();
bool canParseGenericArguments();
bool canParseTypedPattern();
/// Returns true if a qualified declaration name base type can be parsed.
bool canParseBaseTypeForQualifiedDeclName();
/// Returns true if the current token is '->' or effects specifiers followed
/// by '->'.
///
/// e.g.
/// throws -> // true
/// async throws -> // true
/// throws { // false
bool isAtFunctionTypeArrow();
//===--------------------------------------------------------------------===//
// Expression Parsing
ParserResult<Expr> parseExpr(Diag<> ID) {
return parseExprImpl(ID, /*isExprBasic=*/false);
}
ParserResult<Expr> parseExprBasic(Diag<> ID) {
return parseExprImpl(ID, /*isExprBasic=*/true);
}
ParserResult<Expr> parseExprImpl(Diag<> ID, bool isExprBasic);
ParserResult<Expr> parseExprIs();
ParserResult<Expr> parseExprAs();
ParserResult<Expr> parseExprArrow();
ParserResult<Expr> parseExprSequence(Diag<> ID,
bool isExprBasic,
bool isForConditionalDirective = false);
ParserResult<Expr> parseExprSequenceElement(Diag<> ID,
bool isExprBasic);
ParserResult<Expr> parseExprPostfixSuffix(ParserResult<Expr> inner,
bool isExprBasic,
bool periodHasKeyPathBehavior,
bool &hasBindOptional);
ParserResult<Expr> parseExprPostfix(Diag<> ID, bool isExprBasic);
ParserResult<Expr> parseExprPrimary(Diag<> ID, bool isExprBasic);
ParserResult<Expr> parseExprUnary(Diag<> ID, bool isExprBasic);
ParserResult<Expr> parseExprKeyPathObjC();
ParserResult<Expr> parseExprKeyPath();
ParserResult<Expr> parseExprSelector();
ParserResult<Expr> parseExprSuper();
ParserResult<Expr> parseExprStringLiteral();
ParserResult<Expr> parseExprRegexLiteral();
StringRef copyAndStripUnderscores(StringRef text);
StringRef stripUnderscoresIfNeeded(StringRef text,
SmallVectorImpl<char> &buffer);
ParserStatus parseStringSegments(SmallVectorImpl<Lexer::StringSegment> &Segments,
Token EntireTok,
VarDecl *InterpolationVar,
SmallVectorImpl<ASTNode> &Stmts,
unsigned &LiteralCapacity,
unsigned &InterpolationCount);
/// Parse an argument label `identifier ':'`, if it exists.
///
/// \param name The parsed name of the label (empty if it doesn't exist, or is
/// _)
/// \param loc The location of the label (empty if it doesn't exist)
void parseOptionalArgumentLabel(Identifier &name, SourceLoc &loc);
enum class DeclNameFlag : uint8_t {
/// If passed, operator basenames are allowed.
AllowOperators = 1 << 0,
/// If passed, names that coincide with keywords are allowed. Used after a
/// dot to enable things like '.init' and '.default'.
AllowKeywords = 1 << 1,
/// If passed, 'deinit' and 'subscript' should be parsed as special names,
/// not ordinary identifiers.
AllowKeywordsUsingSpecialNames = AllowKeywords | 1 << 2,
/// If passed, compound names with argument lists are allowed, unless they
/// have empty argument lists.
AllowCompoundNames = 1 << 4,
/// If passed, compound names with empty argument lists are allowed.
AllowZeroArgCompoundNames = AllowCompoundNames | 1 << 5,
/// If passed, \c self and \c Self are allowed as basenames. In a lot of
/// cases this doesn't actually make sense but we need to accept them for
/// backwards compatibility.
AllowLowercaseAndUppercaseSelf = 1 << 6,
};
using DeclNameOptions = OptionSet<DeclNameFlag>;
friend DeclNameOptions operator|(DeclNameFlag flag1, DeclNameFlag flag2) {
return DeclNameOptions(flag1) | flag2;
}
/// Without \c DeclNameFlag::AllowCompoundNames, parse an
/// unqualified-decl-base-name.
///
/// unqualified-decl-base-name: identifier
///
/// With \c DeclNameFlag::AllowCompoundNames, parse an unqualified-base-name.
///
/// unqualified-decl-name:
/// unqualified-decl-base-name
/// unqualified-decl-base-name '(' ((identifier | '_') ':') + ')'
DeclNameRef parseDeclNameRef(DeclNameLoc &loc, DiagRef diag,
DeclNameOptions flags);
/// Parse macro expansion.
///
/// macro-expansion:
/// '#' identifier generic-arguments? expr-paren? trailing-closure?
ParserStatus parseFreestandingMacroExpansion(
SourceLoc &poundLoc, DeclNameLoc &macroNameLoc, DeclNameRef &macroNameRef,
SourceLoc &leftAngleLoc, SmallVectorImpl<TypeRepr *> &genericArgs,
SourceLoc &rightAngleLoc, ArgumentList *&argList, bool isExprBasic,
DiagRef diag);
ParserResult<Expr> parseExprIdentifier(bool allowKeyword);
Expr *parseExprEditorPlaceholder(Token PlaceholderTok,
Identifier PlaceholderId);
/// Parse a closure expression after the opening brace.
///
/// \verbatim
/// expr-closure:
/// '{' closure-signature? brace-item-list* '}'
///
/// closure-signature:
/// '|' closure-signature-arguments? '|' closure-signature-result?
///
/// closure-signature-arguments:
/// pattern-tuple-element (',' pattern-tuple-element)*
///
/// closure-signature-result:
/// '->' type
/// \endverbatim
ParserResult<Expr> parseExprClosure();
/// Parse the closure signature, if present.
///
/// \verbatim
/// closure-signature:
/// parameter-clause func-signature-result? 'in'
/// identifier (',' identifier)* func-signature-result? 'in'
/// \endverbatim
///
/// \param bracketRange The range of the brackets enclosing a capture list, if
/// present. Needed to offer fix-its for inserting 'self' into a capture list.
/// \param captureList The entries in the capture list.
/// \param params The parsed parameter list, or null if none was provided.
/// \param arrowLoc The location of the arrow, if present.
/// \param explicitResultType The explicit result type, if specified.
/// \param inLoc The location of the 'in' keyword, if present.
///
/// \returns ParserStatus error if an error occurred. Success if no signature
/// is present or successfully parsed.
ParserStatus parseClosureSignatureIfPresent(
DeclAttributes &attributes,
SourceRange &bracketRange,
SmallVectorImpl<CaptureListEntry> &captureList,
VarDecl *&capturedSelfParamDecl,
ParameterList *&params,
SourceLoc &asyncLoc,
SourceLoc &throwsLoc,
TypeExpr *&thrownType,
SourceLoc &arrowLoc,
TypeExpr *&explicitResultType,
SourceLoc &inLoc);
Expr *parseExprAnonClosureArg();
/// An element of an expression list, which may become e.g a tuple element or
/// argument list argument.
struct ExprListElt {
SourceLoc LabelLoc;
Identifier Label;
Expr *E;
};
/// Parse a tuple or paren expr.
ParserResult<Expr> parseTupleOrParenExpr(tok leftTok, tok rightTok);
/// Parse an argument list.
ParserResult<ArgumentList>
parseArgumentList(tok leftTok, tok rightTok, bool isExprBasic,
bool allowTrailingClosure = true);
ParserStatus parseExprListElement(tok rightTok, bool isArgumentList, SourceLoc leftLoc, SmallVectorImpl<ExprListElt> &elts);
/// Parse one or more trailing closures after an argument list.
ParserStatus parseTrailingClosures(bool isExprBasic, SourceRange calleeRange,
SmallVectorImpl<Argument> &closures);
/// Parse an expression list.
ParserStatus parseExprList(tok leftTok, tok rightTok, bool isArgumentList,
SourceLoc &leftLoc,
SmallVectorImpl<ExprListElt> &elts,
SourceLoc &rightLoc);
/// Parse an object literal.
///
/// \param LK The literal kind as determined by the first token.
ParserResult<Expr> parseExprObjectLiteral(ObjectLiteralExpr::LiteralKind LK,
bool isExprBasic);
ParserResult<Expr> parseExprCallSuffix(ParserResult<Expr> fn,
bool isExprBasic);
ParserResult<Expr> parseExprMacroExpansion(bool isExprBasic);
ParserResult<Expr> parseExprCollection();
ParserResult<Expr>
parseExprCollectionElement(std::optional<bool> &isDictionary);
ParserResult<Expr>
parseExprPoundCodeCompletion(std::optional<StmtKind> ParentKind);
UnresolvedDeclRefExpr *parseExprOperator();
/// Try re-lex a '/' operator character as a regex literal. This should be
/// called when parsing in an expression position to ensure a regex literal is
/// correctly parsed.
void tryLexRegexLiteral(bool forUnappliedOperator);
void validateCollectionElement(ParserResult<Expr> element);
//===--------------------------------------------------------------------===//
// Statement Parsing
/// Whether we are at the start of a statement.
///
/// \param preferExpr If either an expression or statement could be parsed and
/// this parameter is \c true, the function returns \c false such that an
/// expression can be parsed.
bool isStartOfStmt(bool preferExpr);
bool isStartOfConditionalStmtBody();
bool isTerminatorForBraceItemListKind(BraceItemListKind Kind,
ArrayRef<ASTNode> ParsedDecls);
ParserResult<Stmt> parseStmt(bool fromASTGen = false);
ParserStatus parseExprOrStmt(ASTNode &Result);
ParserResult<Stmt> parseStmtBreak();
ParserResult<Stmt> parseStmtContinue();
ParserResult<Stmt> parseStmtReturn(SourceLoc tryLoc);
ParserResult<Stmt> parseStmtYield(SourceLoc tryLoc);
ParserResult<Stmt> parseStmtThen(SourceLoc tryLoc);
ParserResult<Stmt> parseStmtThrow(SourceLoc tryLoc);
ParserResult<Stmt> parseStmtDiscard();
ParserResult<Stmt> parseStmtDefer();
ParserStatus
parseStmtConditionElement(SmallVectorImpl<StmtConditionElement> &result,
Diag<> DefaultID, StmtKind ParentKind,
StringRef &BindingKindStr);
ParserStatus parseStmtCondition(StmtCondition &Result, Diag<> ID,
StmtKind ParentKind);
ParserResult<PoundAvailableInfo> parseStmtConditionPoundAvailable();
ParserResult<PoundHasSymbolInfo> parseStmtConditionPoundHasSymbol();
ParserResult<Stmt> parseStmtIf(LabeledStmtInfo LabelInfo,
bool IfWasImplicitlyInserted = false);
ParserResult<Stmt> parseStmtGuard();
ParserResult<Stmt> parseStmtWhile(LabeledStmtInfo LabelInfo);
ParserResult<Stmt> parseStmtRepeat(LabeledStmtInfo LabelInfo);
ParserResult<Stmt> parseStmtDo(LabeledStmtInfo LabelInfo,
bool shouldSkipDoTokenConsume = false);
ParserResult<CaseStmt> parseStmtCatch();
ParserResult<Stmt> parseStmtForEach(LabeledStmtInfo LabelInfo);
ParserResult<Stmt> parseStmtSwitch(LabeledStmtInfo LabelInfo);
ParserStatus parseStmtCases(SmallVectorImpl<ASTNode> &cases, bool IsActive);
ParserResult<CaseStmt> parseStmtCase(bool IsActive);
ParserResult<Stmt> parseStmtPoundAssert();
//===--------------------------------------------------------------------===//
// Generics Parsing
ParserResult<GenericParamList> parseGenericParameters();
ParserResult<GenericParamList> parseGenericParameters(SourceLoc LAngleLoc);
ParserStatus parseGenericParametersBeforeWhere(SourceLoc LAngleLoc,
SmallVectorImpl<GenericTypeParamDecl *> &GenericParams);
ParserResult<GenericParamList> maybeParseGenericParams();
void
diagnoseWhereClauseInGenericParamList(const GenericParamList *GenericParams);
ParserStatus
parseFreestandingGenericWhereClause(GenericContext *genCtx);
ParserStatus parseGenericWhereClause(
SourceLoc &WhereLoc, SourceLoc &EndLoc,
SmallVectorImpl<RequirementRepr> &Requirements,
bool AllowLayoutConstraints = false);
ParserStatus
parseProtocolOrAssociatedTypeWhereClause(TrailingWhereClause *&trailingWhere,
bool isProtocol);
//===--------------------------------------------------------------------===//
// Availability Specification Parsing
/// The source of an availability spec list.
enum class AvailabilitySpecSource: uint8_t {
/// A spec from '@available(<spec>, ...)' or '#available(<spec>, ...)'.
Available,
/// A spec from '#unavailable(<spec>, ...)'.
Unavailable,
/// A spec from a '-define-availability "Name:<spec>, ..."' frontend arg.
Macro,
};
/// Parse a comma-separated list of availability specifications. Try to
/// expand availability macros when /p Source is not a command line macro.
ParserStatus
parseAvailabilitySpecList(SmallVectorImpl<AvailabilitySpec *> &Specs,
AvailabilitySpecSource Source);
/// Does the current matches an argument macro name? Parsing compiler
/// arguments as required without consuming tokens from the source file
/// parser.
bool peekAvailabilityMacroName();
/// Try to parse a reference to an availability macro and append its result
/// to \p Specs. If the current token doesn't match a macro name, return
/// a success without appending anything to \c Specs.
ParserStatus
parseAvailabilityMacro(SmallVectorImpl<AvailabilitySpec *> &Specs);
/// Parse the availability macros definitions passed as arguments.
void parseAllAvailabilityMacroArguments();
/// Result of parsing an availability macro definition.
struct AvailabilityMacroDefinition {
StringRef Name;
llvm::VersionTuple Version;
SmallVector<AvailabilitySpec *, 4> Specs;
};
/// Parse an availability macro definition from a command line argument.
/// This function should be called on a Parser set up on the command line
/// argument code.
ParserStatus
parseAvailabilityMacroDefinition(AvailabilityMacroDefinition &Result);
ParserResult<AvailabilitySpec> parseAvailabilitySpec();
ParserResult<PlatformVersionConstraintAvailabilitySpec>
parsePlatformVersionConstraintSpec();
ParserResult<PlatformAgnosticVersionConstraintAvailabilitySpec>
parsePlatformAgnosticVersionConstraintSpec();
bool
parseAvailability(bool parseAsPartOfSpecializeAttr, StringRef AttrName,
bool &DiscardAttribute, SourceRange &attrRange,
SourceLoc AtLoc, SourceLoc Loc,
llvm::function_ref<void(AvailableAttr *)> addAttribute);
using PlatformAndVersion = std::pair<PlatformKind, llvm::VersionTuple>;
/// Parse a platform and version tuple (e.g. "macOS 12.0") and append it to
/// the given vector. Wildcards ('*') parse successfully but are ignored.
/// Unrecognized platform names also parse successfully but are ignored.
/// Assumes that the tuples are part of a comma separated list ending with a
/// trailing ')'.
ParserStatus parsePlatformVersionInList(
StringRef AttrName,
llvm::SmallVector<PlatformAndVersion, 4> & PlatformAndVersions,
bool &ParsedUnrecognizedPlatformName);
//===--------------------------------------------------------------------===//
// Code completion second pass.
void performIDEInspectionSecondPassImpl(
IDEInspectionDelayedDeclState &info);
//===--------------------------------------------------------------------===//
// ASTGen support.
/// Parse a TypeRepr from the syntax tree. i.e. SF->getExportedSourceFile()
ParserResult<TypeRepr> parseTypeReprFromSyntaxTree();
/// Parse a Stmt from the syntax tree. i.e. SF->getExportedSourceFile()
ParserResult<Stmt> parseStmtFromSyntaxTree();
/// Parse a Decl from the syntax tree. i.e. SF->getExportedSourceFile()
ParserResult<Decl> parseDeclFromSyntaxTree();
/// Parse an Expr from the syntax tree. i.e. SF->getExportedSourceFile()
ParserResult<Expr> parseExprFromSyntaxTree();
};
/// Describes a parsed declaration name.
struct ParsedDeclName {
/// The name of the context of which the corresponding entity should
/// become a member.
StringRef ContextName;
/// The base name of the declaration.
StringRef BaseName;
/// The argument labels for a function declaration.
SmallVector<StringRef, 4> ArgumentLabels;
/// Whether this is a function name (vs. a value name).
bool IsFunctionName = false;
/// Whether this is a getter for the named property.
bool IsGetter = false;
/// Whether this is a setter for the named property.
bool IsSetter = false;
bool IsSubscript = false;
/// For a declaration name that makes the declaration into an
/// instance member, the index of the "Self" parameter.
std::optional<unsigned> SelfIndex;
/// Determine whether this is a valid name.
explicit operator bool() const { return !BaseName.empty(); }
/// Whether this declaration name turns the declaration into a
/// member of some named context.
bool isMember() const { return !ContextName.empty(); }
/// Whether the result is translated into an instance member.
bool isInstanceMember() const {
return isMember() && static_cast<bool>(SelfIndex);
}
/// Whether the result is translated into a static/class member.
bool isClassMember() const {
return isMember() && !static_cast<bool>(SelfIndex);
}
/// Whether this is a property accessor.
bool isPropertyAccessor() const { return IsGetter || IsSetter; }
/// Whether this is an operator.
bool isOperator() const {
return Lexer::isOperator(BaseName);
}
/// Form a declaration name from this parsed declaration name.
DeclName formDeclName(ASTContext &ctx, bool isSubscript = false,
bool isCxxClassTemplateSpec = false) const;
/// Form a declaration name from this parsed declaration name.
DeclNameRef formDeclNameRef(ASTContext &ctx, bool isSubscript = false,
bool isCxxClassTemplateSpec = false) const;
};
/// To assist debugging parser crashes, tell us the location of the
/// current token.
class PrettyStackTraceParser : public llvm::PrettyStackTraceEntry {
Parser &P;
public:
explicit PrettyStackTraceParser(Parser &P) : P(P) {}
void print(llvm::raw_ostream &out) const override;
};
/// Parse a stringified Swift declaration name,
/// e.g. "Foo.translateBy(self:x:y:)".
ParsedDeclName parseDeclName(StringRef name) LLVM_READONLY;
/// Form a Swift declaration name from its constituent parts.
DeclName formDeclName(ASTContext &ctx,
StringRef baseName,
ArrayRef<StringRef> argumentLabels,
bool isFunctionName,
bool isInitializer,
bool isSubscript = false,
bool isCxxClassTemplateSpec = false);
/// Form a Swift declaration name reference from its constituent parts.
DeclNameRef formDeclNameRef(ASTContext &ctx,
StringRef baseName,
ArrayRef<StringRef> argumentLabels,
bool isFunctionName,
bool isInitializer,
bool isSubscript = false,
bool isCxxClassTemplateSpec = false);
/// Whether a given token can be the start of a decl.
bool isKeywordPossibleDeclStart(const LangOptions &options, const Token &Tok);
} // end namespace swift
#endif