-
Notifications
You must be signed in to change notification settings - Fork 173
/
Copy pathrust-rib.h
221 lines (185 loc) · 6.34 KB
/
rust-rib.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
// 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:
// TODO: Rename the class? to what? Binding? Declaration?
// This is useful for items which are in namespaces where shadowing is not
// allowed, but which are still shadowable! for example, when you do a glob
// import, if a later import has the same name as an item imported in the glob
// import, that glob imported item will need to get shadowed
class Definition
{
public:
static Definition NonShadowable (NodeId id);
static Definition Shadowable (NodeId id);
static Definition Globbed (NodeId id);
// checked shadowable -> non_shadowable -> globbed
// we have shadowable *and* globbed in order to control
// resolution priority
// we *could* use a single vector with 2 indices here
// but it's probably not worth it for now
std::vector<NodeId> ids_shadowable;
std::vector<NodeId> ids_non_shadowable;
std::vector<NodeId> ids_globbed;
Definition () = default;
Definition &operator= (const Definition &) = default;
Definition (Definition const &) = default;
bool is_ambiguous () const;
NodeId get_node_id () const
{
if (!ids_shadowable.empty ())
return ids_shadowable.back ();
rust_assert (!is_ambiguous ());
if (!ids_non_shadowable.empty ())
return ids_non_shadowable.back ();
rust_assert (!ids_globbed.empty ());
return ids_globbed.back ();
}
std::string to_string () const;
private:
enum class Mode
{
SHADOWABLE,
NON_SHADOWABLE,
GLOBBED
};
Definition (NodeId id, Mode mode);
};
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,
/* Prelude rib, used for both the language prelude (i32,usize,etc) and the
* (future) {std,core}::prelude::* import. A regular rib with the
* restriction that you cannot `use` items from the Prelude
*/
Prelude,
} 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 def The `Definition` to insert
*
* @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,
Definition def);
/**
* Access an inserted NodeId.
*
* @return tl::nullopt if the key does not exist, the NodeId otherwise
*/
tl::optional<Rib::Definition> get (const std::string &name);
/* View all the values stored in the rib */
const std::unordered_map<std::string, Definition> &get_values () const;
private:
// TODO: Switch this to (NodeId, shadowable = false);
std::unordered_map<std::string, Definition> values;
};
} // namespace Resolver2_0
} // namespace Rust
#endif // !RUST_RIB_H