mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
While skipping, if we encounter a token that looks
like it could be the start of a `/.../` regex
literal, fall back to parsing the function or type
body normally, as such a token could become a
regex literal. As such, it could treat `{` and
`}` as literal, or otherwise have contents that
would be lexically invalid Swift.
To avoid falling back in too many cases, we apply
the existing regex literal heuristics. Cases that
pass the heuristic fall back to regular parsing.
Cases that fail the heuristic are further checked
to make sure they wouldn't contain an unbalanced
`{` or `}`, but otherwise are allowed to be
skipped. This allows us to continue skipping for
most occurrences of infix and prefix `/`.
This is meant as a lower risk workaround to fix the
the issue, we ought to go back to handling regex
literals in the lexer.
Resolves rdar://95354010
1996 lines
77 KiB
C++
1996 lines
77 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/Expr.h"
|
|
#include "swift/AST/DiagnosticsParse.h"
|
|
#include "swift/AST/LayoutConstraint.h"
|
|
#include "swift/AST/ParseRequests.h"
|
|
#include "swift/AST/Pattern.h"
|
|
#include "swift/AST/Stmt.h"
|
|
#include "swift/Basic/OptionSet.h"
|
|
#include "swift/Parse/Lexer.h"
|
|
#include "swift/Parse/LocalContext.h"
|
|
#include "swift/Parse/PersistentParserState.h"
|
|
#include "swift/Parse/Token.h"
|
|
#include "swift/Parse/ParserPosition.h"
|
|
#include "swift/Parse/ParserResult.h"
|
|
#include "swift/Parse/SyntaxParsingContext.h"
|
|
#include "swift/Syntax/References.h"
|
|
#include "swift/Config.h"
|
|
|
|
namespace llvm {
|
|
template <typename... PTs> class PointerUnion;
|
|
}
|
|
|
|
namespace swift {
|
|
class CodeCompletionCallbacks;
|
|
class CodeCompletionCallbacksFactory;
|
|
class DefaultArgumentInitializer;
|
|
class DiagnosticEngine;
|
|
class Expr;
|
|
class Lexer;
|
|
class ParsedTypeSyntax;
|
|
class PersistentParserState;
|
|
class RequirementRepr;
|
|
class SILParserStateBase;
|
|
class ScopeInfo;
|
|
class SourceManager;
|
|
class TupleType;
|
|
class TypeLoc;
|
|
|
|
struct EnumElementInfo;
|
|
|
|
namespace syntax {
|
|
class RawSyntax;
|
|
enum class SyntaxKind : uint16_t;
|
|
}// end of syntax namespace
|
|
|
|
/// 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 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 Optional<std::vector<Token>> finalize() { return None; }
|
|
|
|
virtual ~ConsumeTokenReceiver() = default;
|
|
};
|
|
|
|
/// 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;
|
|
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 *CodeCompletion = 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.
|
|
Optional<StableHasher> CurrentTokenHash;
|
|
|
|
void recordTokenHash(const Token Tok) {
|
|
if (!Tok.getText().empty())
|
|
recordTokenHash(Tok.getText());
|
|
}
|
|
|
|
void recordTokenHash(StringRef token);
|
|
|
|
enum {
|
|
/// InVarOrLetPattern has this value when not parsing a pattern.
|
|
IVOLP_NotInVarOrLet,
|
|
|
|
/// InVarOrLetPattern has this value when we're in a matching pattern, but
|
|
/// not within a var/let pattern. In this phase, identifiers are references
|
|
/// to the enclosing scopes, not a variable binding.
|
|
IVOLP_InMatchingPattern,
|
|
|
|
/// InVarOrLetPattern has this value when parsing a pattern in which bound
|
|
/// variables are implicitly immutable, but allowed to be marked mutable by
|
|
/// using a 'var' pattern. This happens in for-each loop patterns.
|
|
IVOLP_ImplicitlyImmutable,
|
|
|
|
/// When InVarOrLetPattern has this value, bound variables are mutable, and
|
|
/// nested let/var patterns are not permitted. This happens when parsing a
|
|
/// 'var' decl or when parsing inside a 'var' pattern.
|
|
IVOLP_InVar,
|
|
|
|
/// When InVarOrLetPattern has this value, bound variables are immutable,and
|
|
/// nested let/var patterns are not permitted. This happens when parsing a
|
|
/// 'let' decl or when parsing inside a 'let' pattern.
|
|
IVOLP_InLet
|
|
} InVarOrLetPattern = IVOLP_NotInVarOrLet;
|
|
|
|
/// Whether this context has an async attribute.
|
|
bool InPatternWithAsyncAttribute = false;
|
|
|
|
bool InPoundLineEnvironment = false;
|
|
bool InPoundIfEnvironment = false;
|
|
/// Do not call \c addUnvalidatedDeclWithOpaqueResultType when in an inactive
|
|
/// clause because ASTScopes are not created in those contexts and lookups to
|
|
/// those decls will fail.
|
|
bool InInactiveClauseEnvironment = false;
|
|
bool InSwiftKeyPath = false;
|
|
|
|
LocalContext *CurLocalContext = nullptr;
|
|
|
|
/// 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(CodeCompletionCallbacks *Callbacks) {
|
|
CodeCompletion = Callbacks;
|
|
}
|
|
|
|
bool isCodeCompletionFirstPass() const {
|
|
return L->isCodeCompletion() && !CodeCompletion;
|
|
}
|
|
|
|
bool allowTopLevelCode() 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;
|
|
|
|
/// Leading trivia for \c Tok.
|
|
/// Always empty if !SF.shouldBuildSyntaxTree().
|
|
StringRef LeadingTrivia;
|
|
|
|
/// Trailing trivia for \c Tok.
|
|
/// Always empty if !SF.shouldBuildSyntaxTree().
|
|
StringRef TrailingTrivia;
|
|
|
|
/// 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
|
|
LocalContext *OldLocal;
|
|
|
|
ContextChange(const ContextChange &) = delete;
|
|
ContextChange &operator=(const ContextChange &) = delete;
|
|
|
|
public:
|
|
ContextChange(Parser &P, DeclContext *DC,
|
|
LocalContext *newLocal = nullptr)
|
|
: P(P), OldContext(P.CurDeclContext), OldLocal(P.CurLocalContext) {
|
|
assert(DC && "pushing null context?");
|
|
P.CurDeclContext = DC;
|
|
P.CurLocalContext = newLocal;
|
|
}
|
|
|
|
/// 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;
|
|
P.CurLocalContext = OldLocal;
|
|
}
|
|
};
|
|
|
|
/// A RAII object for parsing a new local context.
|
|
class ParseFunctionBody : public LocalContext {
|
|
private:
|
|
ContextChange CC;
|
|
public:
|
|
ParseFunctionBody(Parser &P, DeclContext *DC) : CC(P, DC, this) {
|
|
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.
|
|
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;
|
|
|
|
/// A RAII object that tells the SyntaxParsingContext to defer Syntax nodes.
|
|
class DeferringContextRAII {
|
|
SyntaxParsingContext &Ctx;
|
|
bool WasDeferring;
|
|
|
|
public:
|
|
explicit DeferringContextRAII(SyntaxParsingContext &SPCtx)
|
|
: Ctx(SPCtx), WasDeferring(Ctx.shouldDefer()) {
|
|
Ctx.setShouldDefer();
|
|
}
|
|
|
|
~DeferringContextRAII() {
|
|
Ctx.setShouldDefer(WasDeferring);
|
|
}
|
|
};
|
|
|
|
/// 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;
|
|
|
|
/// Current syntax parsing context where call backs should be directed to.
|
|
SyntaxParsingContext *SyntaxContext;
|
|
|
|
/// 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,
|
|
std::shared_ptr<SyntaxParseActions> SPActions = nullptr);
|
|
Parser(unsigned BufferID, SourceFile &SF, SILParserStateBase *SIL,
|
|
PersistentParserState *PersistentState = nullptr,
|
|
std::shared_ptr<SyntaxParseActions> SPActions = nullptr);
|
|
Parser(std::unique_ptr<Lexer> Lex, SourceFile &SF,
|
|
SILParserStateBase *SIL = nullptr,
|
|
PersistentParserState *PersistentState = nullptr,
|
|
std::shared_ptr<SyntaxParseActions> SPActions = nullptr);
|
|
~Parser();
|
|
|
|
/// Returns true if the buffer being parsed is allowed to contain SIL.
|
|
bool isInSILMode() const;
|
|
|
|
/// Calling this function to finalize libSyntax tree creation without destroying
|
|
/// the parser instance.
|
|
OpaqueSyntaxNode finalizeSyntaxTree() {
|
|
assert(Tok.is(tok::eof) && "not done parsing yet");
|
|
return SyntaxContext->finalizeRoot();
|
|
}
|
|
|
|
/// 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, LeadingTrivia),
|
|
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, LeadingTrivia, TrailingTrivia);
|
|
PreviousLoc = PP.PreviousLoc;
|
|
}
|
|
|
|
void backtrackToPosition(ParserPosition PP) {
|
|
assert(PP.isValid());
|
|
L->backtrackToState(PP.LS);
|
|
L->lex(Tok, LeadingTrivia, TrailingTrivia);
|
|
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;
|
|
/// This context immediately deconstructed with transparent accumulation
|
|
/// on cancelBacktrack().
|
|
llvm::Optional<SyntaxParsingContext> SynContext;
|
|
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); }
|
|
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) {
|
|
SynContext.emplace(P.SyntaxContext);
|
|
}
|
|
|
|
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) {
|
|
SynContext->disable();
|
|
}
|
|
};
|
|
|
|
/// A backtracking scope whose backtracking can be disabled by calling
|
|
/// \c cancelBacktrack.
|
|
class CancellableBacktrackingScope final : public BacktrackingScopeImpl {
|
|
public:
|
|
CancellableBacktrackingScope(Parser &P) : BacktrackingScopeImpl(P) {
|
|
SynContext->setBackTracking();
|
|
}
|
|
|
|
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 leadingTriviaLoc() {
|
|
return Tok.getLoc().getAdvancedLoc(-LeadingTrivia.size());
|
|
}
|
|
|
|
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())
|
|
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;
|
|
}
|
|
|
|
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());
|
|
}
|
|
|
|
/// 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() && !isStartOfSwiftDecl()) {
|
|
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();
|
|
|
|
/// If the parser is generating only a syntax tree, try loading the current
|
|
/// node from a previously generated syntax tree.
|
|
/// Returns \c true if the node has been loaded and inserted into the current
|
|
/// syntax tree. In this case the parser should behave as if the node has
|
|
/// successfully been created.
|
|
bool loadCurrentSyntaxNodeFromCache();
|
|
|
|
/// 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.
|
|
Optional<StringRef>
|
|
getStringLiteralIfNotInterpolated(SourceLoc Loc, StringRef DiagText);
|
|
|
|
/// Returns true when body elements are eligible as single-expression implicit returns.
|
|
///
|
|
/// \param Body elements to search for implicit single-expression returns.
|
|
bool shouldReturnSingleExpressionElement(ArrayRef<ASTNode> Body);
|
|
|
|
/// 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 ||
|
|
Context.LangOpts.ParseForSyntaxTreeOnly;
|
|
}
|
|
|
|
public:
|
|
InFlightDiagnostic diagnose(SourceLoc Loc, Diagnostic Diag) {
|
|
if (Diags.isDiagnosticPointsToFirstBadToken(Diag.getID()) &&
|
|
Loc == Tok.getLoc() && Tok.isAtStartOfLine())
|
|
Loc = getEndOfPreviousLoc();
|
|
return Diags.diagnose(Loc, Diag);
|
|
}
|
|
|
|
InFlightDiagnostic diagnose(Token Tok, Diagnostic Diag) {
|
|
return diagnose(Tok.getLoc(), Diag);
|
|
}
|
|
|
|
template<typename ...DiagArgTypes, typename ...ArgTypes>
|
|
InFlightDiagnostic diagnose(SourceLoc Loc, Diag<DiagArgTypes...> DiagID,
|
|
ArgTypes &&...Args) {
|
|
return diagnose(Loc, Diagnostic(DiagID, std::forward<ArgTypes>(Args)...));
|
|
}
|
|
|
|
template<typename ...DiagArgTypes, typename ...ArgTypes>
|
|
InFlightDiagnostic diagnose(Token Tok, Diag<DiagArgTypes...> DiagID,
|
|
ArgTypes &&...Args) {
|
|
return diagnose(Tok.getLoc(),
|
|
Diagnostic(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, '>'); }
|
|
|
|
/// 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 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, const Diagnostic &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,
|
|
const Diagnostic &D);
|
|
|
|
template<typename ...DiagArgTypes, typename ...ArgTypes>
|
|
bool parseIdentifier(Identifier &Result, SourceLoc &L,
|
|
bool diagnoseDollarPrefix, Diag<DiagArgTypes...> ID,
|
|
ArgTypes... Args) {
|
|
return parseIdentifier(Result, L, Diagnostic(ID, Args...),
|
|
diagnoseDollarPrefix);
|
|
}
|
|
|
|
template<typename ...DiagArgTypes, typename ...ArgTypes>
|
|
bool parseSpecificIdentifier(StringRef expected,
|
|
Diag<DiagArgTypes...> ID, ArgTypes... Args) {
|
|
SourceLoc L;
|
|
return parseSpecificIdentifier(expected, L, Diagnostic(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,
|
|
const Diagnostic &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, Diagnostic(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,
|
|
const Diagnostic &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, const Diagnostic &D);
|
|
|
|
template<typename ...DiagArgTypes, typename ...ArgTypes>
|
|
bool parseToken(tok K, Diag<DiagArgTypes...> ID, ArgTypes... Args) {
|
|
SourceLoc L;
|
|
return parseToken(K, L, Diagnostic(ID, Args...));
|
|
}
|
|
template<typename ...DiagArgTypes, typename ...ArgTypes>
|
|
bool parseToken(tok K, SourceLoc &L,
|
|
Diag<DiagArgTypes...> ID, ArgTypes... Args) {
|
|
return parseToken(K, L, Diagnostic(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, Diag<> 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,
|
|
SyntaxKind ElementKind,
|
|
llvm::function_ref<ParserStatus()> callback);
|
|
|
|
/// Parse a comma separated list of some elements.
|
|
ParserStatus parseList(tok RightK, SourceLoc LeftLoc, SourceLoc &RightLoc,
|
|
bool AllowSepAfterLast, Diag<> ErrorDiag,
|
|
syntax::SyntaxKind Kind,
|
|
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();
|
|
|
|
/// Returns true if the parser is at the start of a SIL decl.
|
|
bool isStartOfSILDecl();
|
|
|
|
/// Parse the top-level Swift decls into the provided vector.
|
|
void parseTopLevel(SmallVectorImpl<Decl *> &decls);
|
|
|
|
/// 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_AllowDestructor = 1 << 4,
|
|
PD_AllowEnumElement = 1 << 5,
|
|
PD_InProtocol = 1 << 6,
|
|
PD_InClass = 1 << 7,
|
|
PD_InExtension = 1 << 8,
|
|
PD_InStruct = 1 << 9,
|
|
PD_InEnum = 1 << 10,
|
|
};
|
|
|
|
/// Options that control the parsing of declarations.
|
|
using ParseDeclOptions = OptionSet<ParseDeclFlags>;
|
|
|
|
void consumeDecl(ParserPosition BeginParserPosition, ParseDeclOptions Flags,
|
|
bool IsTopLevel);
|
|
|
|
ParserResult<Decl> parseDecl(ParseDeclOptions Flags,
|
|
bool IsAtStartOfLineOrPreviousHadSemi,
|
|
llvm::function_ref<void(Decl*)> Handler);
|
|
|
|
std::pair<std::vector<Decl *>, 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.
|
|
ParserResult<IfConfigDecl> parseIfConfig(
|
|
llvm::function_ref<void(SmallVectorImpl<ASTNode> &, bool)> parseElements);
|
|
|
|
/// 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);
|
|
|
|
void setLocalDiscriminator(ValueDecl *D);
|
|
void setLocalDiscriminatorToParamList(ParameterList *PL);
|
|
|
|
/// Parse the optional attributes before a declaration.
|
|
ParserStatus parseDeclAttributeList(DeclAttributes &Attributes);
|
|
|
|
/// Parse the optional modifiers before a declaration.
|
|
bool 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 the Objective-C selector inside @objc
|
|
void parseObjCSelector(SmallVector<Identifier, 4> &Names,
|
|
SmallVector<SourceLoc, 4> &NameLocs,
|
|
bool &IsNullarySelector);
|
|
|
|
/// 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, AvailabilityContext *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, Optional<bool> &Exported,
|
|
Optional<SpecializeAttr::SpecializationKind> &Kind,
|
|
TrailingWhereClause *&TrailingWhereClause, DeclNameRef &targetFunction,
|
|
AvailabilityContext *SILAvailability,
|
|
SmallVectorImpl<Identifier> &spiGroups,
|
|
SmallVectorImpl<AvailableAttr *> &availableAttrs,
|
|
llvm::function_ref<bool(Parser &)> parseSILTargetName,
|
|
llvm::function_ref<bool(Parser &)> parseSILSIPModule);
|
|
|
|
/// 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 arguments inside the @differentiable attribute.
|
|
bool parseDifferentiableAttributeArguments(
|
|
DifferentiabilityKind &diffKind,
|
|
SmallVectorImpl<ParsedAutoDiffParameter> ¶ms,
|
|
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> ¶meters, 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 @_backDeploy attribute.
|
|
bool parseBackDeployAttribute(DeclAttributes &Attributes, StringRef AttrName,
|
|
SourceLoc AtLoc, SourceLoc Loc);
|
|
|
|
/// Parse a specific attribute.
|
|
ParserStatus parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
|
|
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);
|
|
|
|
bool 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,
|
|
const Diagnostic &D);
|
|
|
|
ParserStatus parseTypeAttributeList(ParamDecl::Specifier &Specifier,
|
|
SourceLoc &SpecifierLoc,
|
|
SourceLoc &IsolatedLoc,
|
|
SourceLoc &ConstLoc,
|
|
TypeAttributes &Attributes) {
|
|
if (Tok.isAny(tok::at_sign, tok::kw_inout) ||
|
|
(Tok.is(tok::identifier) &&
|
|
(Tok.getRawText().equals("__shared") ||
|
|
Tok.getRawText().equals("__owned") ||
|
|
Tok.isContextualKeyword("isolated") ||
|
|
Tok.isContextualKeyword("_const"))))
|
|
return parseTypeAttributeListPresent(
|
|
Specifier, SpecifierLoc, IsolatedLoc, ConstLoc, Attributes);
|
|
return makeParserSuccess();
|
|
}
|
|
|
|
ParserStatus parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier,
|
|
SourceLoc &SpecifierLoc,
|
|
SourceLoc &IsolatedLoc,
|
|
SourceLoc &ConstLoc,
|
|
TypeAttributes &Attributes);
|
|
|
|
bool parseConventionAttributeInternal(bool justChecking,
|
|
TypeAttributes::Convention &convention);
|
|
|
|
ParserStatus parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
|
|
PatternBindingInitializer *&initContext,
|
|
bool justChecking = false);
|
|
|
|
ParserResult<ImportDecl> parseDeclImport(ParseDeclOptions Flags,
|
|
DeclAttributes &Attributes);
|
|
ParserStatus parseInheritance(SmallVectorImpl<InheritedEntry> &Inherited,
|
|
bool allowClassRequirement,
|
|
bool allowAnyObject);
|
|
ParserStatus parseDeclItem(bool &PreviousHadSemi,
|
|
ParseDeclOptions Options,
|
|
llvm::function_ref<void(Decl*)> handler);
|
|
std::pair<std::vector<Decl *>, Optional<Fingerprint>>
|
|
parseDeclList(SourceLoc LBLoc, SourceLoc &RBLoc, Diag<> ErrorDiag,
|
|
ParseDeclOptions Options, IterableDeclContext *IDC,
|
|
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;
|
|
ParserStatus parseGetSet(ParseDeclOptions Flags,
|
|
GenericParamList *GenericParams,
|
|
ParameterList *Indices, TypeRepr *ResultType,
|
|
ParsedAccessors &accessors,
|
|
AbstractStorageDecl *storage, SourceLoc StaticLoc);
|
|
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,
|
|
bool &hasEffectfulGet,
|
|
AccessorKind currentKind,
|
|
SourceLoc const& currentLoc);
|
|
|
|
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);
|
|
|
|
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<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,
|
|
};
|
|
|
|
ParserResult<TypeRepr> parseType();
|
|
ParserResult<TypeRepr> parseType(
|
|
Diag<> MessageID,
|
|
ParseTypeReason reason = ParseTypeReason::Unspecified);
|
|
|
|
/// 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 a type identifier (e.g. 'Foo' or 'Foo.Bar.Baz').
|
|
///
|
|
/// When `isParsingQualifiedDeclBaseType` is true:
|
|
/// - 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.
|
|
ParserResult<TypeRepr> parseTypeIdentifier(
|
|
bool isParsingQualifiedDeclBaseType = false);
|
|
ParserResult<TypeRepr> parseOldStyleProtocolComposition();
|
|
ParserResult<TypeRepr> parseAnyType();
|
|
ParserResult<TypeRepr> parseSILBoxType(GenericParamList *generics,
|
|
const TypeAttributes &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();
|
|
|
|
TypeRepr *applyAttributeToType(TypeRepr *Ty, const TypeAttributes &Attr,
|
|
ParamDecl::Specifier Specifier,
|
|
SourceLoc SpecifierLoc,
|
|
SourceLoc IsolatedLoc,
|
|
SourceLoc ConstLoc);
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// 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 location of the '...', if present.
|
|
SourceLoc EllipsisLoc;
|
|
|
|
/// 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 type following the ':'.
|
|
TypeRepr *Type = nullptr;
|
|
|
|
/// The default argument for this parameter.
|
|
Expr *DefaultArg = nullptr;
|
|
|
|
/// True if this parameter inherits a default argument via '= super'
|
|
bool hasInheritedDefaultArg = false;
|
|
|
|
/// 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,
|
|
};
|
|
|
|
/// Whether we are at the start of a parameter name when parsing a parameter.
|
|
bool startsParameterName(bool isClosure);
|
|
|
|
/// 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> ¶ms,
|
|
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(Identifier functionName,
|
|
DeclName &fullName,
|
|
ParameterList *&bodyParams,
|
|
DefaultArgumentInfo &defaultArgs,
|
|
SourceLoc &asyncLoc,
|
|
bool &reasync,
|
|
SourceLoc &throws,
|
|
bool &rethrows,
|
|
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);
|
|
|
|
/// Returns 'true' if \p T is considered effects specifier.
|
|
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, Optional<TuplePatternElt>>
|
|
parsePatternTupleElement();
|
|
ParserResult<Pattern> parsePatternTuple();
|
|
|
|
ParserResult<Pattern>
|
|
parseOptionalPatternTypeAnnotation(ParserResult<Pattern> P);
|
|
ParserResult<Pattern> parseMatchingPattern(bool isExprBasic);
|
|
ParserResult<Pattern> parseMatchingPatternAsLetOrVar(bool isLet,
|
|
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 canParseSimpleTypeIdentifier();
|
|
|
|
bool canParseTypeIdentifier();
|
|
bool canParseTypeIdentifierOrTypeComposition();
|
|
bool canParseOldStyleProtocolComposition();
|
|
bool canParseTypeTupleBody();
|
|
bool canParseTypeAttribute();
|
|
bool canParseGenericArguments();
|
|
|
|
bool canParseTypedPattern();
|
|
|
|
/// Returns true if a qualified declaration name base type can be parsed.
|
|
///
|
|
/// \verbatim
|
|
/// qualified-decl-name-base-type: simple-type-identifier '.'
|
|
/// \endverbatim
|
|
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);
|
|
|
|
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,
|
|
};
|
|
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, const Diagnostic &diag,
|
|
DeclNameOptions flags);
|
|
|
|
ParserResult<Expr> parseExprIdentifier();
|
|
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 *¶ms,
|
|
SourceLoc &asyncLoc,
|
|
SourceLoc &throwsLoc,
|
|
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);
|
|
|
|
/// 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, SyntaxKind Kind);
|
|
|
|
/// 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> parseExprCollection();
|
|
ParserResult<Expr> parseExprCollectionElement(Optional<bool> &isDictionary);
|
|
ParserResult<Expr> parseExprPoundUnknown(SourceLoc LSquareLoc);
|
|
ParserResult<Expr>
|
|
parseExprPoundCodeCompletion(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
|
|
|
|
bool isStartOfStmt();
|
|
bool isTerminatorForBraceItemListKind(BraceItemListKind Kind,
|
|
ArrayRef<ASTNode> ParsedDecls);
|
|
ParserResult<Stmt> parseStmt();
|
|
ParserStatus parseExprOrStmt(ASTNode &Result);
|
|
ParserResult<Stmt> parseStmtBreak();
|
|
ParserResult<Stmt> parseStmtContinue();
|
|
ParserResult<Stmt> parseStmtReturn(SourceLoc tryLoc);
|
|
ParserResult<Stmt> parseStmtYield(SourceLoc tryLoc);
|
|
ParserResult<Stmt> parseStmtThrow(SourceLoc tryLoc);
|
|
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<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. Assumes
|
|
/// that the tuples are part of a comma separated list ending with a trailing
|
|
/// ')'.
|
|
ParserStatus parsePlatformVersionInList(StringRef AttrName,
|
|
llvm::SmallVector<PlatformAndVersion, 4> &PlatformAndVersions);
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// Code completion second pass.
|
|
|
|
void performCodeCompletionSecondPassImpl(
|
|
CodeCompletionDelayedDeclState &info);
|
|
};
|
|
|
|
/// 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.
|
|
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) const;
|
|
|
|
/// Form a declaration name from this parsed declaration name.
|
|
DeclNameRef formDeclNameRef(ASTContext &ctx, bool isSubscript = 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);
|
|
|
|
/// 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);
|
|
|
|
/// Whether a given token can be the start of a decl.
|
|
bool isKeywordPossibleDeclStart(const Token &Tok);
|
|
|
|
/// Lex and return a vector of `TokenSyntax` tokens, which include
|
|
/// leading and trailing trivia.
|
|
std::vector<
|
|
std::pair<const syntax::RawSyntax *, syntax::AbsoluteOffsetPosition>>
|
|
tokenizeWithTrivia(const LangOptions &LangOpts, const SourceManager &SM,
|
|
unsigned BufferID, const RC<SyntaxArena> &Arena,
|
|
unsigned Offset = 0, unsigned EndOffset = 0,
|
|
DiagnosticEngine *Diags = nullptr);
|
|
} // end namespace swift
|
|
|
|
#endif
|