mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-25 18:00:10 +01:00
125 lines
4.9 KiB
C++
125 lines
4.9 KiB
C++
// 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 <string>
|
|
#include <string_view>
|
|
|
|
#include "common/error.h"
|
|
#include "explorer/ast/value_node.h"
|
|
#include "explorer/base/nonnull.h"
|
|
#include "explorer/base/source_location.h"
|
|
#include "explorer/base/trace_stream.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.
|
|
explicit StaticScope(Nonnull<TraceStream*> trace_stream)
|
|
: ast_node_(std::nullopt), trace_stream_(trace_stream) {}
|
|
|
|
// Construct a scope that is nested within the given scope.
|
|
explicit StaticScope(Nonnull<const StaticScope*> parent,
|
|
std::optional<Nonnull<const AstNode*>> ast_node)
|
|
: parent_scope_(parent),
|
|
ast_node_(ast_node),
|
|
trace_stream_(parent->trace_stream_) {}
|
|
|
|
StaticScope() = default;
|
|
|
|
// 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<Success>;
|
|
|
|
void Print(llvm::raw_ostream& out) const;
|
|
|
|
void PrintID(llvm::raw_ostream& out) const;
|
|
|
|
// 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<ValueNodeView>;
|
|
|
|
// 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<ValueNodeView> this_scope,
|
|
std::string_view name, SourceLocation source_loc,
|
|
bool allow_undeclared) const -> ErrorOr<ValueNodeView>;
|
|
|
|
// Returns the value node of the BindingPattern of the returned var definition
|
|
// if it exists in the ancestor graph.
|
|
auto ResolveReturned() const -> std::optional<ValueNodeView>;
|
|
|
|
// 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<Success>;
|
|
|
|
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<std::optional<ValueNodeView>>;
|
|
|
|
// 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<std::optional<ValueNodeView>>;
|
|
|
|
struct Entry {
|
|
ValueNodeView entity;
|
|
NameStatus status;
|
|
};
|
|
// Maps locally declared names to their entities.
|
|
llvm::StringMap<Entry> declared_names_;
|
|
|
|
// The parent scope of this scope, if it not the root scope.
|
|
std::optional<Nonnull<const StaticScope*>> parent_scope_;
|
|
|
|
// Stores the value node of the BindingPattern of the returned var definition.
|
|
std::optional<ValueNodeView> returned_var_def_view_;
|
|
|
|
std::optional<Nonnull<const AstNode*>> ast_node_;
|
|
|
|
Nonnull<TraceStream*> trace_stream_;
|
|
};
|
|
|
|
} // namespace Carbon
|
|
|
|
#endif // CARBON_EXPLORER_AST_STATIC_SCOPE_H_
|