| //===--- Scope.h - Scope Abstraction ----------------------------*- 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 Sema interface which implement hooks invoked by the |
| // parser to build the AST. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_SEMA_SCOPE_H |
| #define SWIFT_SEMA_SCOPE_H |
| |
| #include "swift/AST/Identifier.h" |
| #include "swift/Basic/TreeScopedHashTable.h" |
| #include "llvm/ADT/SmallVector.h" |
| |
| namespace swift { |
| class ValueDecl; |
| class Parser; |
| class Scope; |
| class SavedScope; |
| |
| /// ScopeInfo - A single instance of this class is maintained by the Parser to |
| /// track the current scope. |
| class ScopeInfo { |
| friend class Scope; |
| public: |
| using ValueScopeEntry = std::pair<unsigned, ValueDecl *>; |
| |
| using ScopedHTTy = TreeScopedHashTable<DeclName, ValueScopeEntry>; |
| using ScopedHTScopeTy = ScopedHTTy::ScopeTy; |
| using ScopedHTDetachedScopeTy = ScopedHTTy::DetachedScopeTy; |
| |
| private: |
| ScopedHTTy HT; |
| |
| Scope *CurScope = nullptr; |
| unsigned ResolvableDepth = 0; |
| |
| public: |
| ValueDecl *lookupValueName(DeclName Name); |
| |
| Scope *getCurrentScope() const { return CurScope; } |
| |
| /// addToScope - Register the specified decl as being in the current lexical |
| /// scope. |
| void addToScope(ValueDecl *D, Parser &TheParser); |
| |
| bool isInactiveConfigBlock() const; |
| |
| SavedScope saveCurrentScope(); |
| |
| LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED, |
| "Only for use in the debugger"); |
| }; |
| |
| enum class ScopeKind { |
| Extension, |
| FunctionBody, |
| Generics, |
| EnumBody, |
| StructBody, |
| ClassBody, |
| ProtocolBody, |
| InheritanceClause, |
| |
| Brace, |
| TopLevel, |
| ForeachVars, |
| CaseVars, |
| CatchVars, |
| WhileVars, |
| IfVars, |
| |
| ClosureParams, |
| }; |
| |
| /// An opaque object that owns the scope frame. The scope frame can be |
| /// re-entered later. |
| class SavedScope { |
| friend class Scope; |
| |
| ScopeInfo::ScopedHTDetachedScopeTy HTDetachedScope; |
| unsigned Depth; |
| ScopeKind Kind; |
| bool IsInactiveConfigBlock; |
| |
| SavedScope() = delete; |
| SavedScope(const SavedScope &) = delete; |
| void operator=(const SavedScope &) = delete; |
| |
| public: |
| SavedScope(SavedScope &&Other) = default; |
| SavedScope &operator=(SavedScope &&) = default; |
| ~SavedScope() = default; |
| |
| SavedScope(ScopeInfo::ScopedHTDetachedScopeTy &&HTDetachedScope, |
| unsigned Depth, ScopeKind Kind, bool isInactiveConfigBlock) |
| : HTDetachedScope(std::move(HTDetachedScope)), Depth(Depth), Kind(Kind), |
| IsInactiveConfigBlock(isInactiveConfigBlock) {} |
| }; |
| |
| /// Scope - This class represents lexical scopes. These objects are created |
| /// and destroyed as the parser is running, and name lookup happens relative |
| /// to them. |
| /// |
| class Scope { |
| friend class ScopeInfo; |
| |
| Scope(const Scope&) = delete; |
| void operator=(const Scope&) = delete; |
| |
| ScopeInfo &SI; |
| ScopeInfo::ScopedHTScopeTy HTScope; |
| |
| Scope *PrevScope; |
| unsigned PrevResolvableDepth; |
| unsigned Depth; |
| ScopeKind Kind; |
| bool IsInactiveConfigBlock; |
| |
| /// Save this scope so that it can be re-entered later. Transfers the |
| /// ownership of the scope frame to returned object. |
| SavedScope saveScope() { |
| return SavedScope(HTScope.detach(), Depth, Kind, IsInactiveConfigBlock); |
| } |
| |
| unsigned getDepth() const { |
| return Depth; |
| } |
| |
| bool isResolvable() const; |
| |
| public: |
| /// Create a lexical scope of the specified kind. |
| Scope(Parser *P, ScopeKind SC, bool isInactiveConfigBlock = false); |
| |
| /// Re-enter the specified scope, transferring the ownership of the |
| /// scope frame to the new object. |
| Scope(Parser *P, SavedScope &&SS); |
| |
| ScopeKind getKind() const { return Kind; } |
| |
| ~Scope() { |
| // Active config blocks delegate to the enclosing scope, so there's nothing |
| // to pop off. |
| assert(SI.CurScope == this && "Scope mismatch"); |
| SI.CurScope = PrevScope; |
| SI.ResolvableDepth = PrevResolvableDepth; |
| } |
| }; |
| |
| inline ValueDecl *ScopeInfo::lookupValueName(DeclName Name) { |
| // FIXME: this check can go away when SIL parser parses everything in |
| // a toplevel scope. |
| if (!CurScope) |
| return nullptr; |
| |
| assert(CurScope && "no scope"); |
| // If we found nothing, or we found a decl at the top-level, return nothing. |
| // We ignore results at the top-level because we may have overloading that |
| // will be resolved properly by name binding. |
| std::pair<unsigned, ValueDecl *> Res = HT.lookup(CurScope->HTScope, Name); |
| if (Res.first < ResolvableDepth) |
| return 0; |
| return Res.second; |
| } |
| |
| inline bool ScopeInfo::isInactiveConfigBlock() const { |
| if (!CurScope) |
| return false; |
| return CurScope->IsInactiveConfigBlock; |
| } |
| |
| inline SavedScope ScopeInfo::saveCurrentScope() { |
| return CurScope->saveScope(); |
| } |
| |
| } // end namespace swift |
| |
| #endif |