//===--- Parser.h - Swift Language Parser -----------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines the Parser interface. // //===----------------------------------------------------------------------===// #ifndef SWIFT_PARSER_H #define SWIFT_PARSER_H #include "swift/AST/ASTContext.h" #include "swift/AST/ASTNode.h" #include "swift/AST/DiagnosticsParse.h" #include "swift/AST/Expr.h" #include "swift/AST/LayoutConstraint.h" #include "swift/AST/Module.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/ParserResult.h" #include "swift/Config.h" #include "llvm/ADT/SetVector.h" namespace llvm { template class PointerUnion3; } namespace swift { class DefaultArgumentInitializer; class DiagnosticEngine; class Lexer; class ScopeInfo; struct TypeLoc; class TupleType; class SILParserState; class SourceManager; class PersistentParserState; class CodeCompletionCallbacks; class DelayedParsingCallbacks; struct EnumElementInfo; /// Different contexts in which BraceItemList are parsed. enum class BraceItemListKind { /// A statement list terminated by a closing brace. The default. Brace, /// A statement list in a case block. The list is terminated /// by a closing brace or a 'case' or 'default' label. Case, /// The top-level of a file, when not in parse-as-library mode (i.e. the /// repl or a script). TopLevelCode, /// The top-level of a file, when in parse-as-library mode. TopLevelLibrary, /// The body of the inactive clause of an #if/#else/#endif block InactiveConditionalBlock, /// The body of the active clause of an #if/#else/#endif block ActiveConditionalBlock, }; class Parser { Parser(const Parser&) = delete; void operator=(const Parser&) = delete; bool IsInputIncomplete = false; SourceLoc DelayedDeclEnd; std::vector SplitTokens; public: SourceManager &SourceMgr; DiagnosticEngine &Diags; SourceFile &SF; Lexer *L; SILParserState *SIL; // Non-null when parsing a .sil file. PersistentParserState *State; std::unique_ptr OwnedState; DeclContext *CurDeclContext; ASTContext &Context; CodeCompletionCallbacks *CodeCompletion = nullptr; std::vector>> AnonClosureVars; bool IsParsingInterfaceTokens = false; /// DisabledVars is a list of variables for whom local name lookup is /// disabled. This is used when parsing a PatternBindingDecl to reject self /// uses and to disable uses of the bound variables in a let/else block. The /// diagnostic to emit is stored in DisabledVarReason. ArrayRef DisabledVars; Diag<> DisabledVarReason; llvm::SmallPtrSet AlreadyHandledDecls; 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; bool InSwiftKeyPath = false; Expr* SwiftKeyPathRoot = nullptr; SourceLoc SwiftKeyPathSlashLoc = SourceLoc(); LocalContext *CurLocalContext = nullptr; DelayedParsingCallbacks *DelayedParseCB = nullptr; bool isDelayedParsingEnabled() const { return DelayedParseCB != nullptr; } void setDelayedParsingCallbacks(DelayedParsingCallbacks *DelayedParseCB) { this->DelayedParseCB = DelayedParseCB; } void setCodeCompletionCallbacks(CodeCompletionCallbacks *Callbacks) { CodeCompletion = Callbacks; } bool isCodeCompletionFirstPass() { return L->isCodeCompletion() && !CodeCompletion; } bool allowTopLevelCode() const { return SF.isScriptMode(); } const std::vector &getSplitTokens() { 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 || Tok.is(tok::eof); } /// \brief This is the current token being considered by the parser. Token Tok; /// \brief 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); } /// 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(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 : unsigned char { /// 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 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 }; void diagnoseOverflow(); public: StructureMarkerRAII(Parser &parser, SourceLoc loc, StructureMarkerKind kind) : P(parser) { P.StructureMarkers.push_back({loc, kind, None}); if (P.StructureMarkers.size() >= MaxDepth) { diagnoseOverflow(); P.cutOffParsing(); } } StructureMarkerRAII(Parser &parser, const Token &tok); ~StructureMarkerRAII() { P.StructureMarkers.pop_back(); } }; friend class StructureMarkerRAII; /// The stack of structure markers indicating the locations of /// structural elements actively being parsed, including the start /// of declarations, statements, and opening operators of various /// kinds. /// /// This vector is managed by \c StructureMarkerRAII objects. llvm::SmallVector StructureMarkers; public: Parser(unsigned BufferID, SourceFile &SF, SILParserState *SIL, PersistentParserState *PersistentState = nullptr); Parser(std::unique_ptr Lex, SourceFile &SF, SILParserState *SIL = nullptr, PersistentParserState *PersistentState = nullptr); ~Parser(); bool isInSILMode() const { return SIL != nullptr; } //===--------------------------------------------------------------------===// // Routines to save and restore parser state. class ParserPosition { public: ParserPosition() = default; ParserPosition &operator=(const ParserPosition &) = default; bool isValid() const { return LS.isValid(); } private: ParserPosition(Lexer::State LS, SourceLoc PreviousLoc): LS(LS), PreviousLoc(PreviousLoc) {} Lexer::State LS; SourceLoc PreviousLoc; friend class Parser; }; ParserPosition getParserPosition() { return ParserPosition(L->getStateForBeginningOfToken(Tok), PreviousLoc); } ParserPosition getParserPosition(const PersistentParserState::ParserPos &Pos){ return ParserPosition(L->getStateForBeginningOfTokenLoc(Pos.Loc), Pos.PrevLoc); } /// \brief Return parser position after the first character of token T ParserPosition getParserPositionAfterFirstCharacter(Token T); void restoreParserPosition(ParserPosition PP, bool enableDiagnostics = false) { L->restoreState(PP.LS, enableDiagnostics); // We might be at tok::eof now, so ensure that consumeToken() does not // assert about lexing past eof. Tok.setKind(tok::unknown); consumeToken(); PreviousLoc = PP.PreviousLoc; } void backtrackToPosition(ParserPosition PP) { assert(PP.isValid()); L->backtrackToState(PP.LS); // We might be at tok::eof now, so ensure that consumeToken() does not // assert about lexing past eof. Tok.setKind(tok::unknown); consumeToken(); 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; bool Backtrack = true; public: BacktrackingScope(Parser &P) : P(P), PP(P.getParserPosition()), DT(P.Diags) {} ~BacktrackingScope() { if (Backtrack) { P.backtrackToPosition(PP); DT.abort(); } } void cancelBacktrack() { Backtrack = false; DT.commit(); } }; /// 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 /// \brief Return the next token that will be installed by \c consumeToken. const Token &peekToken(); SourceLoc consumeToken(); SourceLoc consumeToken(tok K) { assert(Tok.is(K) && "Consuming wrong token kind"); return consumeToken(); } SourceLoc consumeIdentifier(Identifier *Result = nullptr) { assert(Tok.isAny(tok::identifier, tok::kw_self, tok::kw_Self, /* for Swift3 */tok::kw_throws, tok::kw_rethrows)); if (Result) *Result = Context.getIdentifier(Tok.getText()); return consumeToken(); } /// \brief Retrieve the location just past the end of the previous /// source location. SourceLoc getEndOfPreviousLoc(); /// \brief 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; } /// \brief 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); } /// \brief 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(); /// \brief 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 skipUntilDeclRBrace(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(); /// \brief Skip until the next '#else', '#endif' or until eof. void skipUntilConditionalBlockClose(); /// Parse an #endif. bool parseEndIfDirective(SourceLoc &Loc); 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 InFlightDiagnostic diagnose(SourceLoc Loc, Diag DiagID, ArgTypes &&...Args) { return diagnose(Loc, Diagnostic(DiagID, std::forward(Args)...)); } template InFlightDiagnostic diagnose(Token Tok, Diag DiagID, ArgTypes &&...Args) { return diagnose(Tok.getLoc(), Diagnostic(DiagID, std::forward(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; } /// \brief Check whether the current token starts with '<'. bool startsWithLess(Token Tok) { return startsWithSymbol(Tok, '<'); } /// \brief Check whether the current token starts with '>'. bool startsWithGreater(Token Tok) { return startsWithSymbol(Tok, '>'); } /// \brief 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(); /// \brief 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(); /// \brief Consume the starting character of the current token, and split the /// remainder of the token into a new token (or tokens). SourceLoc consumeStartingCharacterOfCurrentToken(); swift::ScopeInfo &getScopeInfo() { return State->getScopeInfo(); } /// \brief Add the given Decl to the current scope. void addToScope(ValueDecl *D) { getScopeInfo().addToScope(D, *this); } ValueDecl *lookupInScope(DeclName Name) { if (Context.LangOpts.EnableASTScopeLookup) return nullptr; return getScopeInfo().lookupValueName(Name); } //===--------------------------------------------------------------------===// // Primitive Parsing /// \brief 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); /// 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 bool parseIdentifier(Identifier &Result, Diag ID, ArgTypes... Args) { SourceLoc L; return parseIdentifier(Result, L, Diagnostic(ID, Args...)); } template bool parseIdentifier(Identifier &Result, SourceLoc &L, Diag ID, ArgTypes... Args) { return parseIdentifier(Result, L, Diagnostic(ID, Args...)); } template bool parseSpecificIdentifier(StringRef expected, Diag ID, ArgTypes... Args) { SourceLoc L; return parseSpecificIdentifier(expected, L, Diagnostic(ID, Args...)); } /// \brief 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); template bool parseAnyIdentifier(Identifier &Result, Diag ID, ArgTypes... Args) { SourceLoc L; return parseAnyIdentifier(Result, L, Diagnostic(ID, Args...)); } template bool parseAnyIdentifier(Identifier &Result, SourceLoc &L, Diag ID, ArgTypes... Args) { return parseAnyIdentifier(Result, L, Diagnostic(ID, Args...)); } /// \brief 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 bool parseToken(tok K, Diag ID, ArgTypes... Args) { SourceLoc L; return parseToken(K, L, Diagnostic(ID, Args...)); } template bool parseToken(tok K, SourceLoc &L, Diag ID, ArgTypes... Args) { return parseToken(K, L, Diagnostic(ID, Args...)); } /// \brief Parse the specified expected token and return its location /// on success. On failure, emit the specified error diagnostic, and /// a note at the specified note location. bool parseMatchingToken(tok K, SourceLoc &TokLoc, Diag<> ErrorDiag, SourceLoc OtherLoc); /// \brief Parse a comma separated list of some elements. ParserStatus parseList(tok RightK, SourceLoc LeftLoc, SourceLoc &RightLoc, bool AllowSepAfterLast, Diag<> ErrorDiag, std::function callback); void consumeTopLevelDecl(ParserPosition BeginParserPosition, TopLevelCodeDecl *TLCD); ParserStatus parseBraceItems(SmallVectorImpl &Decls, BraceItemListKind Kind = BraceItemListKind::Brace, BraceItemListKind ConditionalBlockKind = BraceItemListKind::Brace); ParserResult parseBraceItemList(Diag<> ID); void parseTopLevelCodeDeclDelayed(); //===--------------------------------------------------------------------===// // Decl Parsing /// Return true if parser is at the start of a decl or decl-import. bool isStartOfDecl(); bool parseTopLevel(); /// 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, PD_InLoop = 1 << 11, }; /// Options that control the parsing of declarations. typedef OptionSet ParseDeclOptions; /// Skips the current token if it is '}', and emits a diagnostic. /// /// \returns true if any tokens were skipped. bool skipExtraTopLevelRBraces(); void delayParseFromBeginningToHere(ParserPosition BeginParserPosition, ParseDeclOptions Flags); void consumeDecl(ParserPosition BeginParserPosition, ParseDeclOptions Flags, bool IsTopLevel); // When compiling for the Debugger, some Decl's need to be moved from the // current scope. In which case although the Decl will be returned in the // ParserResult, it should not be inserted into the Decl list for the current // context. markWasHandled asserts that the Decl is already where it // belongs, and declWasHandledAlready is used to check this assertion. // To keep the handled decl array small, we remove the Decl when it is // checked, so you can only call declWasAlreadyHandled once for a given // decl. void markWasHandled(Decl *D) { AlreadyHandledDecls.insert(D); } bool declWasHandledAlready(Decl *D) { return AlreadyHandledDecls.erase(D); } ParserResult parseDecl(ParseDeclOptions Flags, llvm::function_ref Handler); void parseDeclDelayed(); ParserResult parseDeclTypeAlias(ParseDeclOptions Flags, DeclAttributes &Attributes); ParserResult parseDeclAssociatedType(ParseDeclOptions Flags, DeclAttributes &Attributes); /// Parse a #if ... #endif directive. /// Delegate callback function to parse elements in the blocks. ParserResult parseIfConfig( llvm::function_ref &, bool)> parseElements); /// Parse a #line/#sourceLocation directive. /// 'isLine = true' indicates parsing #line instead of #sourcelocation ParserStatus parseLineDirective(bool isLine = false); void setLocalDiscriminator(ValueDecl *D); /// Parse the optional attributes before a declaration. bool parseDeclAttributeList(DeclAttributes &Attributes, bool &FoundCodeCompletionToken); /// 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); /// Parse the @_implements attribute. /// \p Attr is where to store the parsed attribute ParserResult parseImplementsAttribute(SourceLoc AtLoc, SourceLoc Loc); /// Parse a specific attribute. bool 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(clang::VersionTuple &Version, SourceRange &Range, const Diagnostic &D); bool parseTypeAttributeList(SourceLoc &InOutLoc, TypeAttributes &Attributes) { if (Tok.is(tok::at_sign) || Tok.is(tok::kw_inout)) return parseTypeAttributeListPresent(InOutLoc, Attributes); return false; } bool parseTypeAttributeListPresent(SourceLoc &InOutLoc, TypeAttributes &Attributes); bool parseTypeAttribute(TypeAttributes &Attributes, bool justChecking = false); ParserResult parseDeclImport(ParseDeclOptions Flags, DeclAttributes &Attributes); ParserStatus parseInheritance(SmallVectorImpl &Inherited, SourceLoc *classRequirementLoc); ParserStatus parseDeclItem(bool &PreviousHadSemi, Parser::ParseDeclOptions Options, llvm::function_ref handler); bool parseDeclList(SourceLoc LBLoc, SourceLoc &RBLoc, Diag<> ErrorDiag, ParseDeclOptions Options, llvm::function_ref handler); ParserResult parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes); ParserResult parseDeclEnum(ParseDeclOptions Flags, DeclAttributes &Attributes); ParserResult parseDeclEnumCase(ParseDeclOptions Flags, DeclAttributes &Attributes, SmallVectorImpl &decls); ParserResult parseDeclStruct(ParseDeclOptions Flags, DeclAttributes &Attributes); ParserResult parseDeclClass(SourceLoc ClassLoc, ParseDeclOptions Flags, DeclAttributes &Attributes); ParserResult parseDeclVar(ParseDeclOptions Flags, DeclAttributes &Attributes, SmallVectorImpl &Decls, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc TryLoc); void consumeGetSetBody(AbstractFunctionDecl *AFD, SourceLoc LBLoc); struct ParsedAccessors { SourceLoc LBLoc, RBLoc; FuncDecl *Get = nullptr; FuncDecl *Set = nullptr; FuncDecl *Addressor = nullptr; FuncDecl *MutableAddressor = nullptr; FuncDecl *WillSet = nullptr; FuncDecl *DidSet = nullptr; void record(Parser &P, AbstractStorageDecl *storage, bool invalid, ParseDeclOptions flags, SourceLoc staticLoc, const DeclAttributes &attrs, TypeLoc elementTy, ParameterList *indices, SmallVectorImpl &decls); }; bool parseGetSetImpl(ParseDeclOptions Flags, GenericParamList *GenericParams, ParameterList *Indices, TypeLoc ElementTy, ParsedAccessors &accessors, SourceLoc &LastValidLoc, SourceLoc StaticLoc, SourceLoc VarLBLoc, SmallVectorImpl &Decls); bool parseGetSet(ParseDeclOptions Flags, GenericParamList *GenericParams, ParameterList *Indices, TypeLoc ElementTy, ParsedAccessors &accessors, SourceLoc StaticLoc, SmallVectorImpl &Decls); void recordAccessors(AbstractStorageDecl *storage, ParseDeclOptions flags, TypeLoc elementTy, const DeclAttributes &attrs, SourceLoc staticLoc, ParsedAccessors &accessors); void parseAccessorBodyDelayed(AbstractFunctionDecl *AFD); VarDecl *parseDeclVarGetSet(Pattern *pattern, ParseDeclOptions Flags, SourceLoc StaticLoc, bool hasInitializer, const DeclAttributes &Attributes, SmallVectorImpl &Decls); void consumeAbstractFunctionBody(AbstractFunctionDecl *AFD, const DeclAttributes &Attrs); ParserResult parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, ParseDeclOptions Flags, DeclAttributes &Attributes); bool parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD); ParserResult parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes); ParserResult parseDeclSubscript(ParseDeclOptions Flags, DeclAttributes &Attributes, SmallVectorImpl &Decls); ParserResult parseDeclInit(ParseDeclOptions Flags, DeclAttributes &Attributes); ParserResult parseDeclDeinit(ParseDeclOptions Flags, DeclAttributes &Attributes); void addPatternVariablesToScope(ArrayRef Patterns); void addParametersToScope(ParameterList *PL); ParserResult parseDeclOperator(ParseDeclOptions Flags, DeclAttributes &Attributes); ParserResult parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name, SourceLoc NameLoc, DeclAttributes &Attrs); ParserResult parseDeclPrecedenceGroup(ParseDeclOptions flags, DeclAttributes &attributes); //===--------------------------------------------------------------------===// // SIL Parsing. bool parseDeclSIL(); bool parseDeclSILStage(); bool parseSILVTable(); bool parseSILGlobal(); bool parseSILWitnessTable(); bool parseSILDefaultWitnessTable(); bool parseSILCoverageMap(); bool parseSILScope(); //===--------------------------------------------------------------------===// // Type Parsing ParserResult parseType(); ParserResult parseType(Diag<> MessageID, bool HandleCodeCompletion = true, bool IsSILFuncDecl = false); /// \brief Parse any type, but diagnose all types except type-identifier or /// type-composition with non-type-identifier. /// /// In some places the grammar allows only type-identifier, but when it is /// not ambiguous, we want to parse any type for recovery purposes. /// /// \param MessageID a generic diagnostic for a syntax error in the type /// \param NonIdentifierTypeMessageID a diagnostic for a non-identifier type /// /// \returns null, IdentTypeRepr, CompositionTypeRepr or ErrorTypeRepr. ParserResult parseTypeForInheritance(Diag<> MessageID, Diag NonIdentifierTypeMessageID); ParserResult parseTypeSimpleOrComposition(); ParserResult parseTypeSimpleOrComposition(Diag<> MessageID, bool HandleCodeCompletion = true); ParserResult parseTypeSimple(); ParserResult parseTypeSimple(Diag<> MessageID, bool HandleCodeCompletion = true); /// \brief Parse layout constraint. LayoutConstraint parseLayoutConstraint(Identifier LayoutConstraintID); bool parseGenericArguments(SmallVectorImpl &Args, SourceLoc &LAngleLoc, SourceLoc &RAngleLoc); ParserResult parseTypeIdentifier(); ParserResult parseOldStyleProtocolComposition(); ParserResult parseAnyType(); ParserResult parseSILBoxType(GenericParamList *generics, const TypeAttributes &attrs, Optional &GenericsScope); ParserResult parseTypeTupleBody(); ParserResult parseTypeArray(TypeRepr *Base); /// Parse a collection type. /// type-simple: /// '[' type ']' /// '[' type ':' type ']' ParserResult parseTypeCollection(); ParserResult parseTypeOptional(TypeRepr *Base); ParserResult parseTypeImplicitlyUnwrappedOptional(TypeRepr *Base); bool isOptionalToken(const Token &T) const; SourceLoc consumeOptionalToken(); bool isImplicitlyUnwrappedOptionalToken(const Token &T) const; SourceLoc consumeImplicitlyUnwrappedOptionalToken(); TypeRepr *applyAttributeToType(TypeRepr *Ty, SourceLoc InOutLoc, const TypeAttributes &Attr); //===--------------------------------------------------------------------===// // Pattern Parsing /// A structure for collecting information about the default /// arguments of a context. struct DefaultArgumentInfo { llvm::SmallVector 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 for all the initializers to the given /// function. void setFunctionContext(AbstractFunctionDecl *AFD); DefaultArgumentInfo(bool inTypeContext) { NextIndex = inTypeContext ? 1 : 0; HasDefaultArgument = false; } }; /// Describes a parsed parameter. struct ParsedParameter { /// Any declaration attributes attached to the parameter. DeclAttributes Attrs; /// The location of the 'let', 'var', or 'inout' keyword, if present. SourceLoc LetVarInOutLoc; enum SpecifierKindTy { Let, Var, InOut }; SpecifierKindTy SpecifierKind = Let; // Defaults to let. /// 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 we emitted a parse error about this parameter. bool isInvalid = 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, }; /// 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 ¶ms, SourceLoc &rightParenLoc, DefaultArgumentInfo *defaultArgs, ParameterContextKind paramContext); ParserResult parseSingleParameterClause( ParameterContextKind paramContext, SmallVectorImpl *namePieces = nullptr, DefaultArgumentInfo *defaultArgs = nullptr); ParserStatus parseFunctionArguments(SmallVectorImpl &NamePieces, SmallVectorImpl &BodyParams, ParameterContextKind paramContext, DefaultArgumentInfo &defaultArgs); ParserStatus parseFunctionSignature(Identifier functionName, DeclName &fullName, SmallVectorImpl &bodyParams, DefaultArgumentInfo &defaultArgs, SourceLoc &throws, bool &rethrows, TypeRepr *&retType); //===--------------------------------------------------------------------===// // Pattern Parsing ParserResult parseTypedPattern(); ParserResult parsePattern(); /// \brief Parse a tuple pattern element. /// /// \code /// pattern-tuple-element: /// pattern ('=' expr)? /// \endcode /// /// \returns The tuple pattern element, if successful. std::pair> parsePatternTupleElement(); ParserResult parsePatternTuple(); ParserResult parseOptionalPatternTypeAnnotation(ParserResult P, bool isOptional); ParserResult parseMatchingPattern(bool isExprBasic); ParserResult parseMatchingPatternAsLetOrVar(bool isLet, SourceLoc VarLoc, bool isExprBasic); Pattern *createBindingFromPattern(SourceLoc loc, Identifier name, bool isLet); /// \brief 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(); bool canParseTypeIdentifier(); bool canParseTypeIdentifierOrTypeComposition(); bool canParseOldStyleProtocolComposition(); bool canParseTypeTupleBody(); bool canParseTypeAttribute(); bool canParseGenericArguments(); bool canParseTypedPattern(); //===--------------------------------------------------------------------===// // Expression Parsing ParserResult parseExpr(Diag<> ID) { return parseExprImpl(ID, /*isExprBasic=*/false); } ParserResult parseExprBasic(Diag<> ID) { return parseExprImpl(ID, /*isExprBasic=*/true); } ParserResult parseExprImpl(Diag<> ID, bool isExprBasic = false); ParserResult parseExprIs(); ParserResult parseExprAs(); ParserResult parseExprArrow(); ParserResult parseExprSequence(Diag<> ID, bool isExprBasic, bool isForConditionalDirective = false); ParserResult parseExprSequenceElement(Diag<> ID, bool isExprBasic); ParserResult parseExprPostfixSuffix(ParserResult inner, bool isExprBasic, bool periodHasKeyPathBehavior, bool &hasBindOptional); ParserResult parseExprPostfix(Diag<> ID, bool isExprBasic); ParserResult parseExprUnary(Diag<> ID, bool isExprBasic); ParserResult parseExprKeyPathObjC(); ParserResult parseExprKeyPath(); ParserResult parseExprSelector(); ParserResult parseExprSuper(bool isExprBasic); ParserResult parseExprConfiguration(); ParserResult parseExprStringLiteral(); ParserResult parseExprTypeOf(); /// 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); /// Parse an unqualified-decl-name. /// /// unqualified-decl-name: /// identifier /// identifier '(' ((identifier | '_') ':') + ')' /// /// \param afterDot Whether this identifier is coming after a period, which /// enables '.init' and '.default' like expressions. /// \param loc Will be populated with the location of the name. /// \param diag The diagnostic to emit if this is not a name. /// \param allowOperators Whether to allow operator basenames too. /// \param allowZeroArgCompoundNames Whether to allow empty argument lists. DeclName parseUnqualifiedDeclName(bool afterDot, DeclNameLoc &loc, const Diagnostic &diag, bool allowOperators=false, bool allowZeroArgCompoundNames=false); Expr *parseExprIdentifier(); Expr *parseExprEditorPlaceholder(Token PlaceholderTok, Identifier PlaceholderId); /// \brief 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 parseExprClosure(); /// \brief Parse the closure signature, if present. /// /// \verbatim /// closure-signature: /// parameter-clause func-signature-result? 'in' /// identifier (',' identifier)* func-signature-result? 'in' /// \endverbatim /// /// \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 true if an error occurred, false otherwise. bool parseClosureSignatureIfPresent( SmallVectorImpl &captureList, ParameterList *¶ms, SourceLoc &throwsLoc, SourceLoc &arrowLoc, TypeRepr *&explicitResultType, SourceLoc &inLoc); Expr *parseExprAnonClosureArg(); ParserResult parseExprList(tok LeftTok, tok RightTok); /// Parse an expression list, keeping all of the pieces separated. ParserStatus parseExprList(tok leftTok, tok rightTok, bool isPostfix, bool isExprBasic, SourceLoc &leftLoc, SmallVectorImpl &exprs, SmallVectorImpl &exprLabels, SmallVectorImpl &exprLabelLocs, SourceLoc &rightLoc, Expr *&trailingClosure); ParserResult parseTrailingClosure(SourceRange calleeRange); // NOTE: used only for legacy support for old object literal syntax. // Will be removed in the future. bool isCollectionLiteralStartingWithLSquareLit(); /// Parse an object literal. /// /// \param LK The literal kind as determined by the first token. /// \param NewName New name for a legacy literal. ParserResult parseExprObjectLiteral(ObjectLiteralExpr::LiteralKind LK, bool isExprBasic, StringRef NewName = StringRef()); ParserResult parseExprCallSuffix(ParserResult fn, bool isExprBasic); ParserResult parseExprCollection(SourceLoc LSquareLoc = SourceLoc()); ParserResult parseExprArray(SourceLoc LSquareLoc, Expr *FirstExpr); ParserResult parseExprDictionary(SourceLoc LSquareLoc, Expr *FirstKey); UnresolvedDeclRefExpr *parseExprOperator(); //===--------------------------------------------------------------------===// // Statement Parsing bool isStartOfStmt(); ParserResult parseStmt(); ParserStatus parseExprOrStmt(ASTNode &Result); ParserResult parseStmtBreak(); ParserResult parseStmtContinue(); ParserResult parseStmtReturn(SourceLoc tryLoc); ParserResult parseStmtThrow(SourceLoc tryLoc); ParserResult parseStmtDefer(); ParserStatus parseStmtCondition(StmtCondition &Result, Diag<> ID, StmtKind ParentKind); ParserResult parseStmtConditionPoundAvailable(); ParserResult parseStmtIf(LabeledStmtInfo LabelInfo); ParserResult parseStmtGuard(); ParserResult parseStmtWhile(LabeledStmtInfo LabelInfo); ParserResult parseStmtRepeat(LabeledStmtInfo LabelInfo); ParserResult parseStmtDo(LabeledStmtInfo LabelInfo); ParserResult parseStmtCatch(); ParserResult parseStmtFor(LabeledStmtInfo LabelInfo); ParserResult parseStmtForCStyle(SourceLoc ForLoc, LabeledStmtInfo LabelInfo); ParserResult parseStmtForEach(SourceLoc ForLoc, LabeledStmtInfo LabelInfo); ParserResult parseStmtSwitch(LabeledStmtInfo LabelInfo); ParserResult parseStmtCase(); //===--------------------------------------------------------------------===// // Generics Parsing ParserResult parseGenericParameters(); ParserResult parseGenericParameters(SourceLoc LAngleLoc); ParserResult maybeParseGenericParams(); void diagnoseWhereClauseInGenericParamList(const GenericParamList *GenericParams); enum class WhereClauseKind : unsigned { Declaration, Protocol, AssociatedType }; ParserStatus parseFreestandingGenericWhereClause(GenericParamList *&GPList, WhereClauseKind kind=WhereClauseKind::Declaration); ParserStatus parseGenericWhereClause( SourceLoc &WhereLoc, SmallVectorImpl &Requirements, bool &FirstTypeInComplete, bool AllowLayoutConstraints = false); ParserStatus parseProtocolOrAssociatedTypeWhereClause(TrailingWhereClause *&trailingWhere, bool isProtocol); //===--------------------------------------------------------------------===// // Availability Specification Parsing /// Parse a comma-separated list of availability specifications. ParserStatus parseAvailabilitySpecList(SmallVectorImpl &Specs); ParserResult parseAvailabilitySpec(); ParserResult parsePlatformVersionConstraintSpec(); ParserResult parseLanguageVersionConstraintSpec(); }; /// 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 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 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(SelfIndex); } /// Whether the result is translated into a static/class member. bool isClassMember() const { return isMember() && !static_cast(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; }; /// 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 argumentLabels, bool isFunctionName); /// 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); } // end namespace swift #endif