//===--- Stmt.h - Swift Language Statement ASTs -----------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines the Stmt class and subclasses. // //===----------------------------------------------------------------------===// #ifndef SWIFT_AST_STMT_H #define SWIFT_AST_STMT_H #include "swift/AST/Availability.h" #include "swift/AST/AvailabilitySpec.h" #include "swift/AST/ASTNode.h" #include "swift/AST/TypeAlignments.h" #include "swift/Basic/NullablePtr.h" #include "llvm/Support/TrailingObjects.h" namespace swift { class ASTContext; class ASTWalker; class Decl; class Expr; class FuncDecl; class Pattern; class PatternBindingDecl; class VarDecl; enum class StmtKind { #define STMT(ID, PARENT) ID, #define STMT_RANGE(Id, FirstId, LastId) \ First_##Id##Stmt = FirstId, Last_##Id##Stmt = LastId, #include "swift/AST/StmtNodes.def" }; /// Stmt - Base class for all statements in swift. class alignas(8) Stmt { Stmt(const Stmt&) = delete; void operator=(const Stmt&) = delete; /// Kind - The subclass of Stmt that this is. unsigned Kind : 31; /// Implicit - Whether this statement is implicit. unsigned Implicit : 1; protected: /// Return the given value for the 'implicit' flag if present, or if None, /// return true if the location is invalid. static bool getDefaultImplicitFlag(Optional implicit, SourceLoc keyLoc){ return implicit.hasValue() ? *implicit : keyLoc.isInvalid(); } public: Stmt(StmtKind kind, bool implicit) : Kind(unsigned(kind)), Implicit(unsigned(implicit)) {} StmtKind getKind() const { return StmtKind(Kind); } /// \brief Retrieve the name of the given statement kind. /// /// This name should only be used for debugging dumps and other /// developer aids, and should never be part of a diagnostic or exposed /// to the user of the compiler in any way. static StringRef getKindName(StmtKind kind); /// \brief Return the location of the start of the statement. SourceLoc getStartLoc() const; /// \brief Return the location of the end of the statement. SourceLoc getEndLoc() const; SourceRange getSourceRange() const; SourceLoc TrailingSemiLoc; /// isImplicit - Determines whether this statement was implicitly-generated, /// rather than explicitly written in the AST. bool isImplicit() const { return bool(Implicit); } /// walk - This recursively walks the AST rooted at this statement. Stmt *walk(ASTWalker &walker); Stmt *walk(ASTWalker &&walker) { return walk(walker); } LLVM_ATTRIBUTE_DEPRECATED( void dump() const LLVM_ATTRIBUTE_USED, "only for use within the debugger"); void print(raw_ostream &OS, unsigned Indent = 0) const; // Only allow allocation of Exprs using the allocator in ASTContext // or by doing a placement new. void *operator new(size_t Bytes, ASTContext &C, unsigned Alignment = alignof(Stmt)); // Make vanilla new/delete illegal for Stmts. void *operator new(size_t Bytes) throw() = delete; void operator delete(void *Data) throw() = delete; void *operator new(size_t Bytes, void *Mem) throw() = delete; }; /// BraceStmt - A brace enclosed sequence of expressions, stmts, or decls, like /// { var x = 10; print(10) }. class BraceStmt final : public Stmt, private llvm::TrailingObjects { friend TrailingObjects; unsigned NumElements; SourceLoc LBLoc; SourceLoc RBLoc; BraceStmt(SourceLoc lbloc, ArrayRef elements,SourceLoc rbloc, Optional implicit); public: static BraceStmt *create(ASTContext &ctx, SourceLoc lbloc, ArrayRef elements, SourceLoc rbloc, Optional implicit = None); SourceLoc getLBraceLoc() const { return LBLoc; } SourceLoc getRBraceLoc() const { return RBLoc; } SourceRange getSourceRange() const { return SourceRange(LBLoc, RBLoc); } unsigned getNumElements() const { return NumElements; } ASTNode getElement(unsigned i) const { return getElements()[i]; } void setElement(unsigned i, ASTNode node) { getElements()[i] = node; } /// The elements contained within the BraceStmt. MutableArrayRef getElements() { return {getTrailingObjects(), NumElements}; } /// The elements contained within the BraceStmt (const version). ArrayRef getElements() const { return {getTrailingObjects(), NumElements}; } static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Brace; } }; /// ReturnStmt - A return statement. The result is optional; "return" without /// an expression is semantically equivalent to "return ()". /// return 42 class ReturnStmt : public Stmt { SourceLoc ReturnLoc; Expr *Result; public: ReturnStmt(SourceLoc ReturnLoc, Expr *Result, Optional implicit = None) : Stmt(StmtKind::Return, getDefaultImplicitFlag(implicit, ReturnLoc)), ReturnLoc(ReturnLoc), Result(Result) {} SourceLoc getReturnLoc() const { return ReturnLoc; } SourceLoc getStartLoc() const; SourceLoc getEndLoc() const; bool hasResult() const { return Result != 0; } Expr *getResult() const { assert(Result && "ReturnStmt doesn't have a result"); return Result; } void setResult(Expr *e) { Result = e; } static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Return;} }; /// DeferStmt - A 'defer' statement. This runs the substatement it contains /// when the enclosing scope is exited. /// /// defer { cleanUp() } /// /// The AST representation for a defer statement is a bit weird. We model this /// as if they wrote: /// /// func tmpClosure() { body } /// tmpClosure() // This is emitted on each path that needs to run this. /// /// As such, the body of the 'defer' is actually type checked within the /// closure's DeclContext. We do this because of unfortunateness in SILGen, /// some expressions (e.g. OpenExistentialExpr) cannot be multiply emitted in a /// composable way. When this gets fixed, patches r27767 and r27768 can be /// reverted to go back to the simpler and more obvious representation. /// class DeferStmt : public Stmt { SourceLoc DeferLoc; /// This is the bound temp function. FuncDecl *tempDecl; /// This is the invocation of the closure, which is to be emitted on any error /// paths. Expr *callExpr; public: DeferStmt(SourceLoc DeferLoc, FuncDecl *tempDecl, Expr *callExpr) : Stmt(StmtKind::Defer, /*implicit*/false), DeferLoc(DeferLoc), tempDecl(tempDecl), callExpr(callExpr) {} SourceLoc getDeferLoc() const { return DeferLoc; } SourceLoc getStartLoc() const { return DeferLoc; } SourceLoc getEndLoc() const; FuncDecl *getTempDecl() const { return tempDecl; } Expr *getCallExpr() const { return callExpr; } void setCallExpr(Expr *E) { callExpr = E; } /// Dig the original user's body of the defer out for AST fidelity. BraceStmt *getBodyAsWritten() const; static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Defer; } }; /// \brief An expression that guards execution based on whether the run-time /// configuration supports a given API, e.g., /// #available(OSX >= 10.9, iOS >= 7.0). class alignas(8) PoundAvailableInfo final : private llvm::TrailingObjects { friend TrailingObjects; SourceLoc PoundLoc; SourceLoc RParenLoc; // The number of queries tail allocated after this object. unsigned NumQueries; /// The version range when this query will return true. This value is /// filled in by Sema. VersionRange AvailableRange; PoundAvailableInfo(SourceLoc PoundLoc, ArrayRef queries, SourceLoc RParenLoc) : PoundLoc(PoundLoc), RParenLoc(RParenLoc), NumQueries(queries.size()), AvailableRange(VersionRange::empty()) { std::uninitialized_copy(queries.begin(), queries.end(), getTrailingObjects()); } public: static PoundAvailableInfo *create(ASTContext &ctx, SourceLoc PoundLoc, ArrayRef queries, SourceLoc RParenLoc); ArrayRef getQueries() const { return llvm::makeArrayRef(getTrailingObjects(), NumQueries); } SourceLoc getStartLoc() const { return PoundLoc; } SourceLoc getEndLoc() const; SourceLoc getLoc() const { return PoundLoc; } SourceRange getSourceRange() const { return SourceRange(getStartLoc(), getEndLoc()); } const VersionRange &getAvailableRange() const { return AvailableRange; } void setAvailableRange(const VersionRange &Range) { AvailableRange = Range; } void getPlatformKeywordRanges(SmallVectorImpl &PlatformRanges); }; /// This represents an entry in an "if" or "while" condition. Pattern bindings /// can bind any number of names in the pattern binding decl, and may have an /// associated where clause. When "if let" is involved, an arbitrary number of /// pattern bindings and conditional expressions are permitted, e.g.: /// /// if let x = ..., y = ... where x > y, /// let z = ... /// which would be represented as four StmtConditionElement entries, one for /// the "x" binding, one for the "y" binding, one for the where clause, one for /// "z"'s binding. A simple "if" statement is represented as a single binding. /// class StmtConditionElement { /// If this is a pattern binding, it may be the first one in a declaration, in /// which case this is the location of the var/let/case keyword. If this is /// the second pattern (e.g. for 'y' in "var x = ..., y = ...") then this /// location is invalid. SourceLoc IntroducerLoc; /// In a pattern binding, this is pattern being matched. In the case of an /// "implicit optional" pattern, the OptionalSome pattern is explicitly added /// to this as an 'implicit' pattern. Pattern *ThePattern = nullptr; /// This is either the boolean condition, the initializer for a pattern /// binding, or the #available information. llvm::PointerUnion CondInitOrAvailable; public: StmtConditionElement() {} StmtConditionElement(SourceLoc IntroducerLoc, Pattern *ThePattern, Expr *Init) : IntroducerLoc(IntroducerLoc), ThePattern(ThePattern), CondInitOrAvailable(Init) {} StmtConditionElement(Expr *cond) : CondInitOrAvailable(cond) {} StmtConditionElement(PoundAvailableInfo *Info) : CondInitOrAvailable(Info) {} SourceLoc getIntroducerLoc() const { return IntroducerLoc; } void setIntroducerLoc(SourceLoc loc) { IntroducerLoc = loc; } /// ConditionKind - This indicates the sort of condition this is. enum ConditionKind { CK_Boolean, CK_PatternBinding, CK_Availability }; ConditionKind getKind() const { if (ThePattern) return CK_PatternBinding; return CondInitOrAvailable.is() ? CK_Boolean : CK_Availability; } /// Boolean Condition Accessors. Expr *getBooleanOrNull() const { return getKind() == CK_Boolean ? CondInitOrAvailable.get() : nullptr; } Expr *getBoolean() const { assert(getKind() == CK_Boolean && "Not a condition"); return CondInitOrAvailable.get(); } void setBoolean(Expr *E) { assert(getKind() == CK_Boolean && "Not a condition"); CondInitOrAvailable = E; } /// Pattern Binding Accessors. Pattern *getPatternOrNull() const { return ThePattern; } Pattern *getPattern() const { assert(getKind() == CK_PatternBinding && "Not a pattern binding condition"); return ThePattern; } void setPattern(Pattern *P) { assert(getKind() == CK_PatternBinding && "Not a pattern binding condition"); ThePattern = P; } Expr *getInitializer() const { assert(getKind() == CK_PatternBinding && "Not a pattern binding condition"); return CondInitOrAvailable.get(); } void setInitializer(Expr *E) { assert(getKind() == CK_PatternBinding && "Not a pattern binding condition"); CondInitOrAvailable = E; } // Availability Accessors PoundAvailableInfo *getAvailability() const { assert(getKind() == CK_Availability && "Not an #available condition"); return CondInitOrAvailable.get(); } void setAvailability(PoundAvailableInfo *Info) { assert(getKind() == CK_Availability && "Not an #available condition"); CondInitOrAvailable = Info; } SourceLoc getStartLoc() const; SourceLoc getEndLoc() const; SourceRange getSourceRange() const; /// Recursively walks the AST rooted at this statement condition element StmtConditionElement *walk(ASTWalker &walker); StmtConditionElement *walk(ASTWalker &&walker) { return walk(walker); } }; struct LabeledStmtInfo { Identifier Name; SourceLoc Loc; // Evaluates to true if set. operator bool() const { return !Name.empty(); } }; /// LabeledStmt - Common base class between the labeled statements (loops and /// switch). class LabeledStmt : public Stmt { LabeledStmtInfo LabelInfo; protected: SourceLoc getLabelLocOrKeywordLoc(SourceLoc L) const { return LabelInfo ? LabelInfo.Loc : L; } public: LabeledStmt(StmtKind Kind, bool Implicit, LabeledStmtInfo LabelInfo) : Stmt(Kind, Implicit), LabelInfo(LabelInfo) {} LabeledStmtInfo getLabelInfo() const { return LabelInfo; } void setLabelInfo(LabeledStmtInfo L) { LabelInfo = L; } /// Is this statement a valid target of "continue" if labeled? /// /// For the most part, non-looping constructs shouldn't be /// continue-able, but we threw in "do" as a sop. bool isPossibleContinueTarget() const; /// Is this statement a valid target of an unlabeled "break" or /// "continue"? /// /// The nice, consistent language rule is that unlabeled "break" and /// "continue" leave the innermost loop. We have to include /// "switch" (for "break") for consistency with C: Swift doesn't /// require "break" to leave a switch case, but it's still way too /// similar to C's switch to allow different behavior for "break". bool requiresLabelOnJump() const; static bool classof(const Stmt *S) { return S->getKind() >= StmtKind::First_LabeledStmt && S->getKind() <= StmtKind::Last_LabeledStmt; } }; /// DoStmt - do statement, without any trailing clauses. class DoStmt : public LabeledStmt { SourceLoc DoLoc; Stmt *Body; public: DoStmt(LabeledStmtInfo labelInfo, SourceLoc doLoc, Stmt *body, Optional implicit = None) : LabeledStmt(StmtKind::Do, getDefaultImplicitFlag(implicit, doLoc), labelInfo), DoLoc(doLoc), Body(body) {} SourceLoc getDoLoc() const { return DoLoc; } SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(DoLoc); } SourceLoc getEndLoc() const { return Body->getEndLoc(); } Stmt *getBody() const { return Body; } void setBody(Stmt *s) { Body = s; } static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Do; } }; /// An individual 'catch' clause. /// /// This isn't really an independent statement any more than CaseStmt /// is; it's just a structural part of a DoCatchStmt. class CatchStmt : public Stmt { SourceLoc CatchLoc; SourceLoc WhereLoc; Pattern *ErrorPattern; Expr *GuardExpr; Stmt *CatchBody; public: CatchStmt(SourceLoc catchLoc, Pattern *errorPattern, SourceLoc whereLoc, Expr *guardExpr, Stmt *body, Optional implicit = None) : Stmt(StmtKind::Catch, getDefaultImplicitFlag(implicit, catchLoc)), CatchLoc(catchLoc), WhereLoc(whereLoc), ErrorPattern(nullptr), GuardExpr(guardExpr), CatchBody(body) { setErrorPattern(errorPattern); } SourceLoc getCatchLoc() const { return CatchLoc; } /// The location of the 'where' keyword if there's a guard expression. SourceLoc getWhereLoc() const { return WhereLoc; } SourceLoc getStartLoc() const { return CatchLoc; } SourceLoc getEndLoc() const { return CatchBody->getEndLoc(); } Stmt *getBody() const { return CatchBody; } void setBody(Stmt *body) { CatchBody = body; } Pattern *getErrorPattern() { return ErrorPattern; } const Pattern *getErrorPattern() const { return ErrorPattern; } void setErrorPattern(Pattern *pattern); /// Is this catch clause "syntactically exhaustive"? bool isSyntacticallyExhaustive() const; /// Return the guard expression if present, or null if the catch has /// no guard. Expr *getGuardExpr() const { return GuardExpr; } void setGuardExpr(Expr *guard) { GuardExpr = guard; } static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Catch; } }; /// DoCatchStmt - do statement with trailing 'catch' clauses. class DoCatchStmt final : public LabeledStmt, private llvm::TrailingObjects { friend TrailingObjects; SourceLoc DoLoc; Stmt *Body; unsigned NumCatches; DoCatchStmt(LabeledStmtInfo labelInfo, SourceLoc doLoc, Stmt *body, ArrayRef catches, Optional implicit) : LabeledStmt(StmtKind::DoCatch, getDefaultImplicitFlag(implicit, doLoc), labelInfo), DoLoc(doLoc), Body(body), NumCatches(catches.size()) { std::uninitialized_copy(catches.begin(), catches.end(), getTrailingObjects()); } public: static DoCatchStmt *create(ASTContext &ctx, LabeledStmtInfo labelInfo, SourceLoc doLoc, Stmt *body, ArrayRef catches, Optional implicit = None); SourceLoc getDoLoc() const { return DoLoc; } SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(DoLoc); } SourceLoc getEndLoc() const { return getCatches().back()->getEndLoc(); } Stmt *getBody() const { return Body; } void setBody(Stmt *s) { Body = s; } ArrayRef getCatches() const { return {getTrailingObjects(), NumCatches}; } MutableArrayRef getMutableCatches() { return {getTrailingObjects(), NumCatches}; } /// Does this statement contain a syntactically exhaustive catch /// clause? /// /// Note that an exhaustive do/catch statement can still throw /// errors out of its catch block(s). bool isSyntacticallyExhaustive() const; static bool classof(const Stmt *S) { return S->getKind() == StmtKind::DoCatch; } }; /// Either an "if let" case or a simple boolean expression can appear as the /// condition of an 'if' or 'while' statement. using StmtCondition = MutableArrayRef; /// This is the common base class between statements that can have labels, and /// also have complex "if let" style conditions: 'if' and 'while'. class LabeledConditionalStmt : public LabeledStmt { StmtCondition Cond; public: LabeledConditionalStmt(StmtKind Kind, bool Implicit, LabeledStmtInfo LabelInfo, StmtCondition Cond) : LabeledStmt(Kind, Implicit, LabelInfo) { setCond(Cond); } StmtCondition getCond() const { return Cond; } void setCond(StmtCondition e); static bool classof(const Stmt *S) { return S->getKind() >= StmtKind::First_LabeledConditionalStmt && S->getKind() <= StmtKind::Last_LabeledConditionalStmt; } }; /// IfStmt - if/then/else statement. If no 'else' is specified, then the /// ElseLoc location is not specified and the Else statement is null. After /// type-checking, the condition is of type Builtin.Int1. class IfStmt : public LabeledConditionalStmt { SourceLoc IfLoc; SourceLoc ElseLoc; Stmt *Then; Stmt *Else; public: IfStmt(LabeledStmtInfo LabelInfo, SourceLoc IfLoc, StmtCondition Cond, Stmt *Then, SourceLoc ElseLoc, Stmt *Else, Optional implicit = None) : LabeledConditionalStmt(StmtKind::If, getDefaultImplicitFlag(implicit, IfLoc), LabelInfo, Cond), IfLoc(IfLoc), ElseLoc(ElseLoc), Then(Then), Else(Else) {} IfStmt(SourceLoc IfLoc, Expr *Cond, Stmt *Then, SourceLoc ElseLoc, Stmt *Else, Optional implicit, ASTContext &Ctx); SourceLoc getIfLoc() const { return IfLoc; } SourceLoc getElseLoc() const { return ElseLoc; } SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(IfLoc); } SourceLoc getEndLoc() const { return (Else ? Else->getEndLoc() : Then->getEndLoc()); } Stmt *getThenStmt() const { return Then; } void setThenStmt(Stmt *s) { Then = s; } Stmt *getElseStmt() const { return Else; } void setElseStmt(Stmt *s) { Else = s; } // Implement isa/cast/dyncast/etc. static bool classof(const Stmt *S) { return S->getKind() == StmtKind::If; } }; /// GuardStmt - 'guard' statement. Evaluate a condition and if it fails, run /// its body. The body is always guaranteed to exit the current scope (or /// abort), it never falls through. /// class GuardStmt : public LabeledConditionalStmt { SourceLoc GuardLoc; Stmt *Body; public: GuardStmt(SourceLoc GuardLoc, StmtCondition Cond, Stmt *Body, Optional implicit = None) : LabeledConditionalStmt(StmtKind::Guard, getDefaultImplicitFlag(implicit, GuardLoc), LabeledStmtInfo(), Cond), GuardLoc(GuardLoc), Body(Body) {} GuardStmt(SourceLoc GuardLoc, Expr *Cond, Stmt *Body, Optional implicit, ASTContext &Ctx); SourceLoc getGuardLoc() const { return GuardLoc; } SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(GuardLoc); } SourceLoc getEndLoc() const { return Body->getEndLoc(); } Stmt *getBody() const { return Body; } void setBody(Stmt *s) { Body = s; } // Implement isa/cast/dyncast/etc. static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Guard; } }; /// This represents one part of a #if block. If the condition field is /// non-null, then this represents a #if or a #elseif, otherwise it represents /// an #else block. struct IfConfigStmtClause { /// The location of the #if, #elseif, or #else keyword. SourceLoc Loc; /// The condition guarding this #if or #elseif block. If this is null, this /// is a #else clause. Expr *Cond; /// Elements inside the clause ArrayRef Elements; /// True if this is the active clause of the #if block. Since this is /// evaluated at parse time, this is always known. bool isActive; IfConfigStmtClause(SourceLoc Loc, Expr *Cond, ArrayRef Elements, bool isActive) : Loc(Loc), Cond(Cond), Elements(Elements), isActive(isActive) { } }; /// IfConfigStmt - This class models the statement-side representation of /// #if/#else/#endif blocks. class IfConfigStmt : public Stmt { /// An array of clauses controlling each of the #if/#elseif/#else conditions. /// The array is ASTContext allocated. ArrayRef Clauses; SourceLoc EndLoc; bool HadMissingEnd; public: IfConfigStmt(ArrayRef Clauses, SourceLoc EndLoc, bool HadMissingEnd) : Stmt(StmtKind::IfConfig, /*implicit=*/false), Clauses(Clauses), EndLoc(EndLoc), HadMissingEnd(HadMissingEnd) {} SourceLoc getIfLoc() const { return Clauses[0].Loc; } SourceLoc getStartLoc() const { return getIfLoc(); } SourceLoc getEndLoc() const { return EndLoc; } bool hadMissingEnd() const { return HadMissingEnd; } const ArrayRef &getClauses() const { return Clauses; } ArrayRef getActiveClauseElements() const { for (auto &Clause : Clauses) if (Clause.isActive) return Clause.Elements; return ArrayRef(); } // Implement isa/cast/dyncast/etc. static bool classof(const Stmt *S) { return S->getKind() == StmtKind::IfConfig; } }; /// WhileStmt - while statement. After type-checking, the condition is of /// type Builtin.Int1. class WhileStmt : public LabeledConditionalStmt { SourceLoc WhileLoc; StmtCondition Cond; Stmt *Body; public: WhileStmt(LabeledStmtInfo LabelInfo, SourceLoc WhileLoc, StmtCondition Cond, Stmt *Body, Optional implicit = None) : LabeledConditionalStmt(StmtKind::While, getDefaultImplicitFlag(implicit, WhileLoc), LabelInfo, Cond), WhileLoc(WhileLoc), Body(Body) {} SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(WhileLoc); } SourceLoc getEndLoc() const { return Body->getEndLoc(); } Stmt *getBody() const { return Body; } void setBody(Stmt *s) { Body = s; } static bool classof(const Stmt *S) { return S->getKind() == StmtKind::While; } }; /// RepeatWhileStmt - repeat/while statement. After type-checking, the /// condition is of type Builtin.Int1. class RepeatWhileStmt : public LabeledStmt { SourceLoc RepeatLoc, WhileLoc; Stmt *Body; Expr *Cond; public: RepeatWhileStmt(LabeledStmtInfo LabelInfo, SourceLoc RepeatLoc, Expr *Cond, SourceLoc WhileLoc, Stmt *Body, Optional implicit = None) : LabeledStmt(StmtKind::RepeatWhile, getDefaultImplicitFlag(implicit, RepeatLoc), LabelInfo), RepeatLoc(RepeatLoc), WhileLoc(WhileLoc), Body(Body), Cond(Cond) {} SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(RepeatLoc); } SourceLoc getEndLoc() const; Stmt *getBody() const { return Body; } void setBody(Stmt *s) { Body = s; } Expr *getCond() const { return Cond; } void setCond(Expr *e) { Cond = e; } static bool classof(const Stmt *S) {return S->getKind() == StmtKind::RepeatWhile;} }; /// ForStmt - for statement. After type-checking, the condition is of /// type Builtin.Int1. Note that the condition is optional. If not present, /// it always evaluates to true. The Initializer and Increment are also /// optional. class ForStmt : public LabeledStmt { SourceLoc ForLoc, Semi1Loc, Semi2Loc; NullablePtr Initializer; ArrayRef InitializerVarDecls; NullablePtr Cond; NullablePtr Increment; Stmt *Body; public: ForStmt(LabeledStmtInfo LabelInfo, SourceLoc ForLoc, NullablePtr Initializer, ArrayRef InitializerVarDecls, SourceLoc Semi1Loc, NullablePtr Cond, SourceLoc Semi2Loc, NullablePtr Increment, Stmt *Body, Optional implicit = None) : LabeledStmt(StmtKind::For, getDefaultImplicitFlag(implicit, ForLoc), LabelInfo), ForLoc(ForLoc), Semi1Loc(Semi1Loc), Semi2Loc(Semi2Loc), Initializer(Initializer), InitializerVarDecls(InitializerVarDecls), Cond(Cond), Increment(Increment), Body(Body) { } SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(ForLoc); } SourceLoc getEndLoc() const { return Body->getEndLoc(); } SourceLoc getFirstSemicolonLoc() const { return Semi1Loc; } SourceLoc getSecondSemicolonLoc() const { return Semi2Loc; } NullablePtr getInitializer() const { return Initializer; } void setInitializer(Expr *V) { Initializer = V; } ArrayRef getInitializerVarDecls() const { return InitializerVarDecls; } void setInitializerVarDecls(ArrayRef D) { InitializerVarDecls = D; } NullablePtr getCond() const { return Cond; } void setCond(NullablePtr C) { Cond = C; } NullablePtr getIncrement() const { return Increment; } void setIncrement(Expr *V) { Increment = V; } Stmt *getBody() const { return Body; } void setBody(Stmt *s) { Body = s; } static bool classof(const Stmt *S) { return S->getKind() == StmtKind::For; } }; /// ForEachStmt - foreach statement that iterates over the elements in a /// container. /// /// Example: /// \code /// for i in 0...10 { /// print(String(i)) /// } /// \endcode class ForEachStmt : public LabeledStmt { SourceLoc ForLoc; Pattern *Pat; SourceLoc InLoc; Expr *Sequence; Expr *WhereExpr = nullptr; BraceStmt *Body; /// The iterator variable along with its initializer. PatternBindingDecl *Iterator = nullptr; /// The expression that advances the iterator and returns an Optional with /// the next value or None to signal end-of-stream. Expr *IteratorNext = nullptr; public: ForEachStmt(LabeledStmtInfo LabelInfo, SourceLoc ForLoc, Pattern *Pat, SourceLoc InLoc, Expr *Sequence, Expr *WhereExpr, BraceStmt *Body, Optional implicit = None) : LabeledStmt(StmtKind::ForEach, getDefaultImplicitFlag(implicit, ForLoc), LabelInfo), ForLoc(ForLoc), Pat(nullptr), InLoc(InLoc), Sequence(Sequence), WhereExpr(WhereExpr), Body(Body) { setPattern(Pat); } /// getForLoc - Retrieve the location of the 'for' keyword. SourceLoc getForLoc() const { return ForLoc; } /// getInLoc - Retrieve the location of the 'in' keyword. SourceLoc getInLoc() const { return InLoc; } /// getPattern - Retrieve the pattern describing the iteration variables. /// These variables will only be visible within the body of the loop. Pattern *getPattern() const { return Pat; } void setPattern(Pattern *p); Expr *getWhere() const { return WhereExpr; } void setWhere(Expr *W) { WhereExpr = W; } /// getSequence - Retrieve the Sequence whose elements will be visited /// by this foreach loop, as it was written in the source code and /// subsequently type-checked. To determine the semantic behavior of this /// expression to extract a range, use \c getRangeInit(). Expr *getSequence() const { return Sequence; } void setSequence(Expr *S) { Sequence = S; } /// Retrieve the pattern binding that contains the (implicit) iterator /// variable and its initialization from the container. PatternBindingDecl *getIterator() const { return Iterator; } void setIterator(PatternBindingDecl *It) { Iterator = It; } /// Retrieve the expression that advances the iterator. Expr *getIteratorNext() const { return IteratorNext; } void setIteratorNext(Expr *E) { IteratorNext = E; } /// getBody - Retrieve the body of the loop. BraceStmt *getBody() const { return Body; } void setBody(BraceStmt *B) { Body = B; } SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(ForLoc); } SourceLoc getEndLoc() const { return Body->getEndLoc(); } static bool classof(const Stmt *S) { return S->getKind() == StmtKind::ForEach; } }; /// A pattern and an optional guard expression used in a 'case' statement. class CaseLabelItem { Pattern *CasePattern; SourceLoc WhereLoc; llvm::PointerIntPair GuardExprAndIsDefault; public: CaseLabelItem(const CaseLabelItem &) = default; CaseLabelItem(bool IsDefault, Pattern *CasePattern, SourceLoc WhereLoc, Expr *GuardExpr) : CasePattern(CasePattern), WhereLoc(WhereLoc), GuardExprAndIsDefault(GuardExpr, IsDefault) {} SourceLoc getWhereLoc() const { return WhereLoc; } SourceLoc getStartLoc() const; SourceLoc getEndLoc() const; SourceRange getSourceRange() const; Pattern *getPattern() { return CasePattern; } const Pattern *getPattern() const { return CasePattern; } void setPattern(Pattern *CasePattern) { this->CasePattern = CasePattern; } /// Return the guard expression if present, or null if the case label has /// no guard. Expr *getGuardExpr() { return GuardExprAndIsDefault.getPointer(); } const Expr *getGuardExpr() const { return GuardExprAndIsDefault.getPointer(); } void setGuardExpr(Expr *e) { GuardExprAndIsDefault.setPointer(e); } /// Returns true if this is syntactically a 'default' label. bool isDefault() const { return GuardExprAndIsDefault.getInt(); } }; /// A 'case' or 'default' block of a switch statement. Only valid as the /// substatement of a SwitchStmt. A case block begins either with one or more /// CaseLabelItems or a single 'default' label. /// /// Some examples: /// \code /// case 1: /// case 2, 3: /// case Foo(var x, var y) where x < y: /// case 2 where foo(), 3 where bar(): /// default: /// \endcode /// class CaseStmt final : public Stmt, private llvm::TrailingObjects { friend TrailingObjects; SourceLoc CaseLoc; SourceLoc ColonLoc; llvm::PointerIntPair BodyAndHasBoundDecls; unsigned NumPatterns; CaseStmt(SourceLoc CaseLoc, ArrayRef CaseLabelItems, bool HasBoundDecls, SourceLoc ColonLoc, Stmt *Body, Optional Implicit); public: static CaseStmt *create(ASTContext &C, SourceLoc CaseLoc, ArrayRef CaseLabelItems, bool HasBoundDecls, SourceLoc ColonLoc, Stmt *Body, Optional Implicit = None); ArrayRef getCaseLabelItems() const { return {getTrailingObjects(), NumPatterns}; } MutableArrayRef getMutableCaseLabelItems() { return {getTrailingObjects(), NumPatterns}; } Stmt *getBody() const { return BodyAndHasBoundDecls.getPointer(); } void setBody(Stmt *body) { BodyAndHasBoundDecls.setPointer(body); } /// True if the case block declares any patterns with local variable bindings. bool hasBoundDecls() const { return BodyAndHasBoundDecls.getInt(); } /// Get the source location of the 'case' or 'default' of the first label. SourceLoc getLoc() const { return CaseLoc; } SourceLoc getStartLoc() const { return getLoc(); } SourceLoc getEndLoc() const { return getBody()->getEndLoc(); } SourceRange getLabelItemsRange() const { return ColonLoc.isValid() ? SourceRange(getLoc(), ColonLoc) : getSourceRange(); } bool isDefault() { return getCaseLabelItems()[0].isDefault(); } static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Case; } }; /// Switch statement. class SwitchStmt final : public LabeledStmt, private llvm::TrailingObjects { friend TrailingObjects; SourceLoc SwitchLoc, LBraceLoc, RBraceLoc; Expr *SubjectExpr; unsigned CaseCount; SwitchStmt(LabeledStmtInfo LabelInfo, SourceLoc SwitchLoc, Expr *SubjectExpr, SourceLoc LBraceLoc, unsigned CaseCount, SourceLoc RBraceLoc, Optional implicit = None) : LabeledStmt(StmtKind::Switch, getDefaultImplicitFlag(implicit, SwitchLoc), LabelInfo), SwitchLoc(SwitchLoc), LBraceLoc(LBraceLoc), RBraceLoc(RBraceLoc), SubjectExpr(SubjectExpr), CaseCount(CaseCount) {} public: /// Allocate a new SwitchStmt in the given ASTContext. static SwitchStmt *create(LabeledStmtInfo LabelInfo, SourceLoc SwitchLoc, Expr *SubjectExpr, SourceLoc LBraceLoc, ArrayRef Cases, SourceLoc RBraceLoc, ASTContext &C); /// Get the source location of the 'switch' keyword. SourceLoc getSwitchLoc() const { return SwitchLoc; } /// Get the source location of the opening brace. SourceLoc getLBraceLoc() const { return LBraceLoc; } /// Get the source location of the closing brace. SourceLoc getRBraceLoc() const { return RBraceLoc; } SourceLoc getLoc() const { return SwitchLoc; } SourceLoc getStartLoc() const { return getLabelLocOrKeywordLoc(SwitchLoc); } SourceLoc getEndLoc() const { return RBraceLoc; } /// Get the subject expression of the switch. Expr *getSubjectExpr() const { return SubjectExpr; } void setSubjectExpr(Expr *e) { SubjectExpr = e; } /// Get the list of case clauses. ArrayRef getCases() const { return {getTrailingObjects(), CaseCount}; } static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Switch; } }; /// BreakStmt - The "break" and "break label" statement. class BreakStmt : public Stmt { SourceLoc Loc; Identifier TargetName; // Named target statement, if specified in the source. SourceLoc TargetLoc; LabeledStmt *Target; // Target stmt, wired up by Sema. public: BreakStmt(SourceLoc Loc, Identifier TargetName, SourceLoc TargetLoc, Optional implicit = None) : Stmt(StmtKind::Break, getDefaultImplicitFlag(implicit, Loc)), Loc(Loc), TargetName(TargetName), TargetLoc(TargetLoc) { } SourceLoc getLoc() const { return Loc; } Identifier getTargetName() const { return TargetName; } void setTargetName(Identifier N) { TargetName = N; } SourceLoc getTargetLoc() const { return TargetLoc; } void setTargetLoc(SourceLoc L) { TargetLoc = L; } // Manipulate the target loop/switch that is bring broken out of. This is set // by sema during type checking. void setTarget(LabeledStmt *LS) { Target = LS; } LabeledStmt *getTarget() const { return Target; } SourceLoc getStartLoc() const { return Loc; } SourceLoc getEndLoc() const { return (TargetLoc.isValid() ? TargetLoc : Loc); } static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Break; } }; /// ContinueStmt - The "continue" and "continue label" statement. class ContinueStmt : public Stmt { SourceLoc Loc; Identifier TargetName; // Named target statement, if specified in the source. SourceLoc TargetLoc; LabeledStmt *Target; public: ContinueStmt(SourceLoc Loc, Identifier TargetName, SourceLoc TargetLoc, Optional implicit = None) : Stmt(StmtKind::Continue, getDefaultImplicitFlag(implicit, Loc)), Loc(Loc), TargetName(TargetName), TargetLoc(TargetLoc) { } Identifier getTargetName() const { return TargetName; } void setTargetName(Identifier N) { TargetName = N; } SourceLoc getTargetLoc() const { return TargetLoc; } void setTargetLoc(SourceLoc L) { TargetLoc = L; } // Manipulate the target loop that is bring continued. This is set by sema // during type checking. void setTarget(LabeledStmt *LS) { Target = LS; } LabeledStmt *getTarget() const { return Target; } SourceLoc getLoc() const { return Loc; } SourceLoc getStartLoc() const { return Loc; } SourceLoc getEndLoc() const { return (TargetLoc.isValid() ? TargetLoc : Loc); } static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Continue; } }; /// FallthroughStmt - The keyword "fallthrough". class FallthroughStmt : public Stmt { SourceLoc Loc; CaseStmt *FallthroughDest; public: FallthroughStmt(SourceLoc Loc, Optional implicit = None) : Stmt(StmtKind::Fallthrough, getDefaultImplicitFlag(implicit, Loc)), Loc(Loc), FallthroughDest(nullptr) {} SourceLoc getLoc() const { return Loc; } SourceRange getSourceRange() const { return Loc; } /// Get the CaseStmt block to which the fallthrough transfers control. /// Set during Sema. CaseStmt *getFallthroughDest() const { assert(FallthroughDest && "fallthrough dest is not set until Sema"); return FallthroughDest; } void setFallthroughDest(CaseStmt *C) { assert(!FallthroughDest && "fallthrough dest already set?!"); FallthroughDest = C; } static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Fallthrough; } }; /// FailStmt - A statement that indicates a failable, which is currently /// spelled as "return nil" and can only be used within failable initializers. class FailStmt : public Stmt { SourceLoc ReturnLoc; SourceLoc NilLoc; public: FailStmt(SourceLoc returnLoc, SourceLoc nilLoc, Optional implicit = None) : Stmt(StmtKind::Fail, getDefaultImplicitFlag(implicit, returnLoc)), ReturnLoc(returnLoc), NilLoc(nilLoc) {} SourceLoc getLoc() const { return ReturnLoc; } SourceRange getSourceRange() const { return SourceRange(ReturnLoc, NilLoc); } static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Fail; } }; /// ThrowStmt - Throws an error. class ThrowStmt : public Stmt { Expr *SubExpr; SourceLoc ThrowLoc; public: explicit ThrowStmt(SourceLoc throwLoc, Expr *subExpr) : Stmt(StmtKind::Throw, /*Implicit=*/false), SubExpr(subExpr), ThrowLoc(throwLoc) {} SourceLoc getThrowLoc() const { return ThrowLoc; } SourceLoc getStartLoc() const { return ThrowLoc; } SourceLoc getEndLoc() const; SourceRange getSourceRange() const { return SourceRange(ThrowLoc, getEndLoc()); } Expr *getSubExpr() const { return SubExpr; } void setSubExpr(Expr *subExpr) { SubExpr = subExpr; } static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Throw; } }; } // end namespace swift #endif