// Part of the Carbon Language project, under the Apache License v2.0 with LLVM // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #ifndef CARBON_EXPLORER_AST_STATIC_SCOPE_H_ #define CARBON_EXPLORER_AST_STATIC_SCOPE_H_ #include #include #include "common/error.h" #include "explorer/ast/value_node.h" #include "explorer/common/nonnull.h" #include "explorer/common/source_location.h" #include "llvm/ADT/StringMap.h" namespace Carbon { // Maps the names visible in a given scope to the entities they name. // A scope may have parent scopes, whose names will also be visible in the // child scope. class StaticScope { public: // The status of a name. Later enumerators with higher values correspond to // more completely declared names. enum class NameStatus { // The name is known to exist in this scope, and any lookups finding it // should be rejected because it's not declared yet. KnownButNotDeclared, // We've started processing a declaration of this name, but it's not yet // fully declared, so any lookups finding it should be rejected. DeclaredButNotUsable, // The name is usable in this context. Usable, }; // Construct a root scope. StaticScope() = default; // Construct a scope that is nested within the given scope. explicit StaticScope(Nonnull parent) : parent_scope_(parent) {} // Defines `name` to be `entity` in this scope, or reports a compilation error // if `name` is already defined to be a different entity in this scope. // If `usable` is `false`, `name` cannot yet be referenced and `Resolve()` // methods will fail for it. auto Add(std::string_view name, ValueNodeView entity, NameStatus status = NameStatus::Usable) -> ErrorOr; // Marks `name` as being past its point of declaration. void MarkDeclared(std::string_view name); // Marks `name` as being completely declared and hence usable. void MarkUsable(std::string_view name); // Returns the nearest declaration of `name` in the ancestor graph of this // scope, or reports a compilation error at `source_loc` there isn't such a // declaration. // TODO: This should also diagnose if there's a shadowed declaration of the // name in an enclosing scope, but does not do so yet. auto Resolve(std::string_view name, SourceLocation source_loc) const -> ErrorOr; // Returns the declaration of `name` in this scope, or reports a compilation // error at `source_loc` if the name is not declared in this scope. If // `allow_undeclared` is `true`, names that have been added but not yet marked // declared or usable do not result in an error. auto ResolveHere(std::optional this_scope, std::string_view name, SourceLocation source_loc, bool allow_undeclared) const -> ErrorOr; // Returns the value node of the BindingPattern of the returned var definition // if it exists in the ancestor graph. auto ResolveReturned() const -> std::optional; // Adds the value node of the BindingPattern of the returned var definition to // this scope. Returns a compilation error when there is an existing returned // var in the ancestor graph. auto AddReturnedVar(ValueNodeView returned_var_def_view) -> ErrorOr; private: // Equivalent to Resolve, but returns `nullopt` instead of raising an error // if no declaration can be found. auto TryResolve(std::string_view name, SourceLocation source_loc) const -> ErrorOr>; // Equivalent to ResolveHere, but returns `nullopt` if no definition can be // found. Raises an error if the name is found but is not usable yet. auto TryResolveHere(std::string_view name, SourceLocation source_loc, bool allow_undeclared) const -> ErrorOr>; struct Entry { ValueNodeView entity; NameStatus status; }; // Maps locally declared names to their entities. llvm::StringMap declared_names_; // The parent scope of this scope, if it not the root scope. std::optional> parent_scope_; // Stores the value node of the BindingPattern of the returned var definition. std::optional returned_var_def_view_; }; } // namespace Carbon #endif // CARBON_EXPLORER_AST_STATIC_SCOPE_H_