| //===--- 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 AbsolutePosition; |
| class RawSyntax; |
| enum class SyntaxKind; |
| }// 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(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<llvm::MD5> 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; |
| |
| 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 trivias for \c Tok. |
| /// Always empty if !SF.shouldBuildSyntaxTree(). |
| ParsedTrivia LeadingTrivia; |
| |
| /// trailing trivias for \c Tok. |
| /// Always empty if !SF.shouldBuildSyntaxTree(). |
| ParsedTrivia TrailingTrivia; |
| |
| /// The receiver to collect all consumed tokens. |
| ConsumeTokenReceiver *TokReceiver; |
| |
| /// The location of the previous token. |
| SourceLoc PreviousLoc; |
| |
| /// Stop parsing immediately. |
| void cutOffParsing() { |
| // Cut off parsing by acting as if we reached the end-of-file. |
| Tok.setKind(tok::eof); |
| } |
| |
| /// 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 *const P; |
| |
| /// Max nesting level |
| // TODO: customizable. |
| enum { MaxDepth = 256 }; |
| |
| StructureMarkerRAII(Parser *parser) : P(parser) {} |
| |
| /// Have the parser start the new Structure or fail if already too deep. |
| bool pushStructureMarker(Parser &parser, SourceLoc loc, |
| StructureMarkerKind kind); |
| |
| public: |
| StructureMarkerRAII(Parser &parser, SourceLoc loc, StructureMarkerKind kind) |
| : StructureMarkerRAII( |
| pushStructureMarker(parser, loc, kind) ? &parser : nullptr) {} |
| |
| StructureMarkerRAII(Parser &parser, const Token &tok); |
| |
| /// Did we fail to push the new structure? |
| bool isFailed() { |
| return P == nullptr; |
| } |
| |
| ~StructureMarkerRAII() { |
| if (P != nullptr) { |
| 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. |
| class BacktrackingScope { |
| 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(Token tok) override { |
| delayedTokens.push_back(tok); |
| } |
| Optional<std::vector<Token>> finalize() override { |
| llvm_unreachable("Cannot finalize a DelayedTokenReciever"); |
| } |
| ~DelayedTokenReceiver() { |
| if (!shouldTransfer) |
| return; |
| for (auto tok: delayedTokens) { |
| savedConsumer.get()->receive(tok); |
| } |
| } |
| } TempReceiver; |
| |
| public: |
| BacktrackingScope(Parser &P) |
| : P(P), PP(P.getParserPosition()), DT(P.Diags), |
| TempReceiver(P.TokReceiver) { |
| SynContext.emplace(P.SyntaxContext); |
| SynContext->setBackTracking(); |
| } |
| |
| ~BacktrackingScope(); |
| bool willBacktrack() const { return Backtrack; } |
| |
| 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(); |
| |
| /// 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.getLength()); |
| } |
| |
| 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) { |
| 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=*/true); |
| } |
| 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. |
| void 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(); |
| |
| void skipUntilDeclStmtRBrace(tok T1); |
| void skipUntilDeclStmtRBrace(tok T1, tok T2); |
| |
| 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. |
| void 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 a braced block (e.g. function body). The current token must be '{'. |
| /// Returns \c true if the parser hit the eof before finding matched '}'. |
| /// |
| /// Set \c HasNestedTypeDeclarations to true if a token for a type |
| /// declaration is detected in the skipped block. |
| bool skipBracedBlock(bool &HasNestedTypeDeclarations); |
| |
| /// Skip over SIL decls until we encounter the start of a Swift decl or eof. |
| void skipSILUntilSwiftDecl(); |
| |
| /// 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)...)); |
| } |
| |
| void diagnoseRedefinition(ValueDecl *Prev, ValueDecl *New); |
| |
| /// 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 preceed 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; |
| |
| /// 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(); |
| |
| /// 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 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); |
| |
| /// 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, |
| 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, |
| SmallVectorImpl<Identifier> &spiGroups, |
| 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( |
| bool &linear, 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 a specific attribute. |
| ParserStatus parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc); |
| |
| bool parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc, |
| DeclAttrKind DK); |
| |
| /// 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); |
| |
| bool parseTypeAttributeList(ParamDecl::Specifier &Specifier, |
| SourceLoc &SpecifierLoc, |
| TypeAttributes &Attributes) { |
| if (Tok.isAny(tok::at_sign, tok::kw_inout) || |
| (Tok.is(tok::identifier) && |
| (Tok.getRawText().equals("__shared") || |
| Tok.getRawText().equals("__owned")))) |
| return parseTypeAttributeListPresent(Specifier, SpecifierLoc, Attributes); |
| return false; |
| } |
| bool parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier, |
| SourceLoc &SpecifierLoc, |
| TypeAttributes &Attributes); |
| |
| bool parseConventionAttributeInternal(bool justChecking, |
| TypeAttributes::Convention &convention); |
| |
| bool parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc, |
| bool justChecking = false); |
| |
| |
| ParserResult<ImportDecl> parseDeclImport(ParseDeclOptions Flags, |
| DeclAttributes &Attributes); |
| ParserStatus parseInheritance(SmallVectorImpl<TypeLoc> &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, |
| 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); |
| |
| void consumeAbstractFunctionBody(AbstractFunctionDecl *AFD, |
| const DeclAttributes &Attrs); |
| ParserResult<FuncDecl> parseDeclFunc(SourceLoc StaticLoc, |
| StaticSpellingKind StaticSpelling, |
| ParseDeclOptions Flags, |
| DeclAttributes &Attributes, |
| bool HasFuncKeyword = true); |
| BraceStmt *parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD); |
| void parseAbstractFunctionBody(AbstractFunctionDecl *AFD); |
| BraceStmt *parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD); |
| 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 |
| |
| ParserResult<TypeRepr> parseType(); |
| ParserResult<TypeRepr> parseType(Diag<> MessageID, |
| bool IsSILFuncDecl = false); |
| |
| ParserResult<TypeRepr> |
| parseTypeSimpleOrComposition(Diag<> MessageID); |
| |
| ParserResult<TypeRepr> parseTypeSimple(Diag<> MessageID); |
| |
| /// 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(TypeRepr *Base); |
| |
| /// Parse a collection type. |
| /// type-simple: |
| /// '[' type ']' |
| /// '[' type ':' type ']' |
| ParserResult<TypeRepr> parseTypeCollection(); |
| |
| ParserResult<TypeRepr> parseTypeOptional(TypeRepr *Base); |
| |
| ParserResult<TypeRepr> parseTypeImplicitlyUnwrappedOptional(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); |
| |
| //===--------------------------------------------------------------------===// |
| // 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 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, |
| }; |
| |
| /// 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, |
| 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 rethrows If non-NULL, will also parse the 'rethrows' keyword in |
| /// lieu of 'throws'. |
| ParserStatus parseEffectsSpecifiers(SourceLoc existingArrowLoc, |
| SourceLoc &asyncLoc, 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(); |
| |
| 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); |
| |
| 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 succssfully parsed. |
| ParserStatus parseClosureSignatureIfPresent( |
| SourceRange &bracketRange, |
| SmallVectorImpl<CaptureListEntry> &captureList, |
| VarDecl *&capturedSelfParamDecl, |
| ParameterList *¶ms, |
| SourceLoc &asyncLoc, |
| SourceLoc &throwsLoc, |
| SourceLoc &arrowLoc, |
| TypeExpr *&explicitResultType, |
| SourceLoc &inLoc); |
| |
| Expr *parseExprAnonClosureArg(); |
| ParserResult<Expr> parseExprList(tok LeftTok, tok RightTok, |
| syntax::SyntaxKind Kind); |
| |
| /// Parse an expression list, keeping all of the pieces separated. |
| ParserStatus parseExprList(tok leftTok, tok rightTok, |
| bool isPostfix, |
| bool isExprBasic, |
| SourceLoc &leftLoc, |
| SmallVectorImpl<Expr *> &exprs, |
| SmallVectorImpl<Identifier> &exprLabels, |
| SmallVectorImpl<SourceLoc> &exprLabelLocs, |
| SourceLoc &rightLoc, |
| SmallVectorImpl<TrailingClosure> &trailingClosures, |
| syntax::SyntaxKind Kind); |
| |
| ParserStatus |
| parseTrailingClosures(bool isExprBasic, SourceRange calleeRange, |
| SmallVectorImpl<TrailingClosure> &closures); |
| |
| /// 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(); |
| |
| 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 |
| |
| /// Parse a comma-separated list of availability specifications. Try to |
| /// expand availability macros when /p ParsingMacroDefinition is false. |
| ParserStatus |
| parseAvailabilitySpecList(SmallVectorImpl<AvailabilitySpec *> &Specs, |
| bool ParsingMacroDefinition = false); |
| |
| /// 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(); |
| |
| //===--------------------------------------------------------------------===// |
| // 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; |
| |
| /// 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) const; |
| |
| /// Form a declaration name from this parsed declaration name. |
| DeclNameRef formDeclNameRef(ASTContext &ctx) 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); |
| |
| /// Form a Swift declaration name referemce from its constituent parts. |
| DeclNameRef formDeclNameRef(ASTContext &ctx, |
| StringRef baseName, |
| ArrayRef<StringRef> argumentLabels, |
| bool isFunctionName, |
| bool isInitializer); |
| |
| /// Parse a stringified Swift declaration name, e.g. "init(frame:)". |
| DeclName parseDeclName(ASTContext &ctx, StringRef name); |
| |
| /// 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<RC<syntax::RawSyntax>, |
| syntax::AbsolutePosition>> |
| tokenizeWithTrivia(const LangOptions &LangOpts, |
| const SourceManager &SM, |
| unsigned BufferID, |
| unsigned Offset = 0, |
| unsigned EndOffset = 0, |
| DiagnosticEngine *Diags = nullptr); |
| } // end namespace swift |
| |
| #endif |