mirror of https://github.com/gcc-mirror/gcc.git
162 lines
4.6 KiB
C++
162 lines
4.6 KiB
C++
// Copyright (C) 2020-2024 Free Software Foundation, Inc.
|
|
|
|
// This file is part of GCC.
|
|
|
|
// GCC is free software; you can redistribute it and/or modify it under
|
|
// the terms of the GNU General Public License as published by the Free
|
|
// Software Foundation; either version 3, or (at your option) any later
|
|
// version.
|
|
|
|
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
// for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with GCC; see the file COPYING3. If not see
|
|
// <http://www.gnu.org/licenses/>.
|
|
|
|
#ifndef RUST_RIB_H
|
|
#define RUST_RIB_H
|
|
|
|
#include "rust-system.h"
|
|
#include "rust-ast.h"
|
|
#include "optional.h"
|
|
#include "expected.h"
|
|
|
|
namespace Rust {
|
|
namespace Resolver2_0 {
|
|
|
|
/**
|
|
|
|
pub enum Namespace {
|
|
/// The type namespace includes `struct`s, `enum`s, `union`s, `trait`s, and
|
|
`mod`s
|
|
/// (and, by extension, crates).
|
|
///
|
|
/// Note that the type namespace includes other items; this is not an
|
|
/// exhaustive list.
|
|
TypeNS,
|
|
/// The value namespace includes `fn`s, `const`s, `static`s, and local
|
|
variables (including function arguments). ValueNS,
|
|
/// The macro namespace includes `macro_rules!` macros, declarative `macro`s,
|
|
/// procedural macros, attribute macros, `derive` macros, and non-macro
|
|
attributes
|
|
/// like `#[inline]` and `#[rustfmt::skip]`.
|
|
MacroNS,
|
|
}
|
|
|
|
*/
|
|
|
|
// FIXME: There's no `labels` namespace, not sure if we need one or how to keep
|
|
// one
|
|
// FIXME: And where are things like loop labels kept?
|
|
|
|
/**
|
|
* All namespaces that Rust's name resolution needs to handle
|
|
*/
|
|
// TODO: Move to `rust-forever-stack.h`?
|
|
enum class Namespace
|
|
{
|
|
Values,
|
|
Types,
|
|
Labels,
|
|
Macros,
|
|
// TODO: Which namespaces are we missing?
|
|
};
|
|
|
|
/**
|
|
* Error returned by `Rib::insert` when the key was already present in the Rib's
|
|
* map. The class contains the previously-inserted NodeId as well as the name of
|
|
* the node.
|
|
*/
|
|
struct DuplicateNameError
|
|
{
|
|
// TODO: We might need multiple kinds of errors later down the line
|
|
DuplicateNameError (std::string name, NodeId existing);
|
|
|
|
std::string name;
|
|
NodeId existing;
|
|
};
|
|
|
|
/**
|
|
* A rib is a container of nodes, either declaration or usages, as well as the
|
|
* identifier each node uses. They are used to delimit lexical scopes, and have
|
|
* an impact on name resolution - they restrict certain name accesses and serve
|
|
* as boundaries between scopes.
|
|
|
|
* For example, if we are resolving the following *variable* use:
|
|
*
|
|
* ```rust
|
|
* fn outer() {
|
|
* let a = 15; // decl
|
|
* fn inner() -> i32 {
|
|
* a // use
|
|
* }
|
|
* }
|
|
* ```
|
|
*
|
|
* The `Function` rib we will have pushed will restrict the access to `outer`'s
|
|
* `a` declaration: Variable uses cannot cross function boundaries. On the other
|
|
* hand, if we were resolving a type usage, this would be perfectly allowed.
|
|
*/
|
|
class Rib
|
|
{
|
|
public:
|
|
enum class Kind
|
|
{
|
|
Normal,
|
|
Module,
|
|
Function,
|
|
ConstantItem, // -> this variant has a boolean
|
|
TraitOrImpl,
|
|
/* Any item other than a Module, Function, Constant, Trait or Impl block */
|
|
Item,
|
|
Closure,
|
|
MacroDefinition,
|
|
/* Ban the use of forward-declared generic parameters in defaults */
|
|
ForwardTypeParamBan,
|
|
/* Const generic, as in the following example: fn foo<T, const X: T>() {} */
|
|
ConstParamType,
|
|
} kind;
|
|
|
|
Rib (Kind kind);
|
|
Rib (Kind kind, std::string identifier, NodeId id);
|
|
Rib (Kind kind, std::unordered_map<std::string, NodeId> values);
|
|
|
|
// TODO: What's the correctbehavior if the key already exists? What if a decl
|
|
// and use are in the same rib? Is that possible? Okay based on RibKind?
|
|
|
|
/**
|
|
* Insert a new node in the rib
|
|
*
|
|
* @param name The name associated with the AST node
|
|
* @param id Its NodeId
|
|
* @param can_shadow If the newly inserted value can shadow an existing one
|
|
*
|
|
* @return `DuplicateNameError` if the node is already present in the rib. The
|
|
* `DuplicateNameError` class contains the NodeId of the existing
|
|
* node. Returns the new NodeId on success.
|
|
*/
|
|
tl::expected<NodeId, DuplicateNameError> insert (std::string name, NodeId id,
|
|
bool can_shadow = false);
|
|
|
|
/**
|
|
* Access an inserted NodeId.
|
|
*
|
|
* @return tl::nullopt if the key does not exist, the NodeId otherwise
|
|
*/
|
|
tl::optional<NodeId> get (const std::string &name);
|
|
|
|
/* View all the values stored in the rib */
|
|
const std::unordered_map<std::string, NodeId> &get_values () const;
|
|
|
|
private:
|
|
std::unordered_map<std::string, NodeId> values;
|
|
};
|
|
|
|
} // namespace Resolver2_0
|
|
} // namespace Rust
|
|
|
|
#endif // !RUST_RIB_H
|