Line data Source code
1 : // Copyright (C) 2024-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #include "expected.h"
20 : #include "rust-ast.h"
21 : #include "rust-diagnostics.h"
22 : #include "rust-forever-stack.h"
23 : #include "rust-rib.h"
24 : #include "optional.h"
25 :
26 : namespace Rust {
27 : namespace Resolver2_0 {
28 :
29 : bool
30 0 : ForeverStackStore::Node::is_root () const
31 : {
32 0 : return !parent.has_value ();
33 : }
34 :
35 : bool
36 0 : ForeverStackStore::Node::is_leaf () const
37 : {
38 0 : return children.empty ();
39 : }
40 :
41 : NodeId
42 0 : ForeverStackStore::Node::get_id () const
43 : {
44 0 : return id;
45 : }
46 :
47 : ForeverStackStore::Node &
48 0 : ForeverStackStore::Node::insert_child (NodeId id, tl::optional<Identifier> path,
49 : Rib::Kind kind)
50 : {
51 0 : auto res = children.insert ({Link (id, path), Node (kind, id, *this)});
52 :
53 0 : rust_debug ("inserting link: Link(%d [%s]): existed? %s", id,
54 : path.has_value () ? path.value ().as_string ().c_str ()
55 : : "<anon>",
56 : !res.second ? "yes" : "no");
57 :
58 : // sanity check on rib kind
59 : // pick the value rib, since all ribs should have the same kind anyways
60 0 : rust_assert (res.second || res.first->second.value_rib.kind == kind);
61 :
62 : // verify, if we're using an existing node, our paths don't contradict
63 0 : if (!res.second && path.has_value ())
64 : {
65 0 : auto other_path = res.first->first.path;
66 0 : rust_assert (!other_path.has_value ()
67 : || other_path.value ().as_string ()
68 : == path.value ().as_string ());
69 0 : }
70 :
71 0 : return res.first->second;
72 : }
73 :
74 : tl::optional<ForeverStackStore::Node &>
75 0 : ForeverStackStore::Node::get_child (const Identifier &path)
76 : {
77 0 : for (auto &ent : children)
78 : {
79 0 : if (ent.first.path.has_value ()
80 0 : && ent.first.path->as_string () == path.as_string ())
81 0 : return ent.second;
82 : }
83 0 : return tl::nullopt;
84 : }
85 :
86 : tl::optional<const ForeverStackStore::Node &>
87 0 : ForeverStackStore::Node::get_child (const Identifier &path) const
88 : {
89 0 : for (auto &ent : children)
90 : {
91 0 : if (ent.first.path.has_value ()
92 0 : && ent.first.path->as_string () == path.as_string ())
93 0 : return ent.second;
94 : }
95 0 : return tl::nullopt;
96 : }
97 :
98 : tl::optional<ForeverStackStore::Node &>
99 0 : ForeverStackStore::Node::get_parent ()
100 : {
101 0 : return parent;
102 : }
103 :
104 : tl::optional<const ForeverStackStore::Node &>
105 0 : ForeverStackStore::Node::get_parent () const
106 : {
107 0 : if (parent)
108 0 : return *parent;
109 0 : return tl::nullopt;
110 : }
111 :
112 : tl::optional<const Identifier &>
113 0 : ForeverStackStore::Node::get_parent_path () const
114 : {
115 0 : if (parent.has_value ())
116 0 : for (auto &ent : parent->children)
117 0 : if (ent.first.id == id && ent.first.path.has_value ())
118 0 : return ent.first.path.value ();
119 0 : return tl::nullopt;
120 : }
121 :
122 : Rib &
123 0 : ForeverStackStore::Node::get_rib (Namespace ns)
124 : {
125 0 : switch (ns)
126 : {
127 0 : case Namespace::Values:
128 0 : return value_rib;
129 0 : case Namespace::Types:
130 0 : return type_rib;
131 0 : case Namespace::Labels:
132 0 : return label_rib;
133 0 : case Namespace::Macros:
134 0 : return macro_rib;
135 0 : default:
136 0 : rust_unreachable ();
137 : }
138 : }
139 :
140 : const Rib &
141 0 : ForeverStackStore::Node::get_rib (Namespace ns) const
142 : {
143 0 : switch (ns)
144 : {
145 0 : case Namespace::Values:
146 0 : return value_rib;
147 0 : case Namespace::Types:
148 0 : return type_rib;
149 0 : case Namespace::Labels:
150 0 : return label_rib;
151 0 : case Namespace::Macros:
152 0 : return macro_rib;
153 0 : default:
154 0 : rust_unreachable ();
155 : }
156 : }
157 :
158 : tl::expected<NodeId, DuplicateNameError>
159 0 : ForeverStackStore::Node::insert (const Identifier &name, NodeId node,
160 : Namespace ns)
161 : {
162 : // So what do we do here - if the Rib has already been pushed in an earlier
163 : // pass, we might end up in a situation where it is okay to re-add new names.
164 : // Do we just ignore that here? Do we keep track of if the Rib is new or not?
165 : // should our cursor have info on the current node like "is it newly pushed"?
166 0 : return get_rib (ns).insert (name.as_string (),
167 0 : Rib::Definition::NonShadowable (node));
168 : }
169 :
170 : tl::expected<NodeId, DuplicateNameError>
171 0 : ForeverStackStore::Node::insert_shadowable (const Identifier &name, NodeId node,
172 : Namespace ns)
173 : {
174 0 : return get_rib (ns).insert (name.as_string (),
175 0 : Rib::Definition::Shadowable (node));
176 : }
177 :
178 : tl::expected<NodeId, DuplicateNameError>
179 0 : ForeverStackStore::Node::insert_globbed (const Identifier &name, NodeId node,
180 : Namespace ns)
181 : {
182 0 : return get_rib (ns).insert (name.as_string (),
183 0 : Rib::Definition::Globbed (node));
184 : }
185 :
186 : void
187 0 : ForeverStackStore::Node::reverse_iter (std::function<KeepGoing (Node &)> lambda)
188 : {
189 0 : for (Node *tmp = this; lambda (*tmp) == KeepGoing::Yes && !tmp->is_root ();
190 0 : tmp = &tmp->parent.value ())
191 : ;
192 0 : }
193 :
194 : void
195 0 : ForeverStackStore::Node::reverse_iter (
196 : std::function<KeepGoing (const Node &)> lambda) const
197 : {
198 0 : for (const Node *tmp = this;
199 0 : lambda (*tmp) == KeepGoing::Yes && !tmp->is_root ();
200 0 : tmp = &tmp->parent.value ())
201 : ;
202 0 : }
203 :
204 : void
205 0 : ForeverStackStore::Node::child_iter (
206 : std::function<KeepGoing (NodeId, tl::optional<const Identifier &>, Node &)>
207 : lambda)
208 : {
209 0 : for (auto &ent : children)
210 : {
211 0 : tl::optional<const Identifier &> path;
212 0 : if (ent.first.path.has_value ())
213 0 : path = ent.first.path.value ();
214 0 : auto keep_going = lambda (ent.first.id, path, ent.second);
215 0 : if (keep_going == KeepGoing::No)
216 0 : return;
217 : }
218 : }
219 :
220 : void
221 0 : ForeverStackStore::Node::child_iter (
222 : std::function<KeepGoing (NodeId, tl::optional<const Identifier &>,
223 : const Node &)>
224 : lambda) const
225 : {
226 0 : for (auto &ent : children)
227 : {
228 0 : tl::optional<const Identifier &> path;
229 0 : if (ent.first.path.has_value ())
230 0 : path = ent.first.path.value ();
231 0 : auto keep_going = lambda (ent.first.id, path, ent.second);
232 0 : if (keep_going == KeepGoing::No)
233 0 : return;
234 : }
235 : }
236 :
237 : ForeverStackStore::Node &
238 0 : ForeverStackStore::Node::find_closest_module ()
239 : {
240 : // get kind of value_rib
241 : // but all ribs should share the same kind anyways
242 0 : if (value_rib.kind == Rib::Kind::Module || !parent.has_value ())
243 0 : return *this;
244 : else
245 0 : return parent->find_closest_module ();
246 : }
247 :
248 : const ForeverStackStore::Node &
249 0 : ForeverStackStore::Node::find_closest_module () const
250 : {
251 : // get kind of value_rib
252 : // but all ribs should share the same kind anyways
253 0 : if (value_rib.kind != Rib::Kind::Module || !parent.has_value ())
254 0 : return *this;
255 : else
256 0 : return parent->find_closest_module ();
257 : }
258 :
259 : tl::optional<ForeverStackStore::Node &>
260 0 : ForeverStackStore::Node::dfs_node (NodeId to_find)
261 : {
262 0 : if (id == to_find)
263 0 : return *this;
264 :
265 0 : for (auto &child : children)
266 : {
267 0 : auto candidate = child.second.dfs_node (to_find);
268 :
269 0 : if (candidate.has_value ())
270 0 : return candidate;
271 : }
272 :
273 0 : return tl::nullopt;
274 : }
275 :
276 : tl::optional<const ForeverStackStore::Node &>
277 0 : ForeverStackStore::Node::dfs_node (NodeId to_find) const
278 : {
279 0 : if (id == to_find)
280 0 : return *this;
281 :
282 0 : for (auto &child : children)
283 : {
284 0 : auto candidate = child.second.dfs_node (to_find);
285 :
286 0 : if (candidate.has_value ())
287 0 : return candidate;
288 : }
289 :
290 0 : return tl::nullopt;
291 : }
292 :
293 : ForeverStackStore::Node &
294 0 : ForeverStackStore::get_root ()
295 : {
296 0 : return root;
297 : }
298 :
299 : const ForeverStackStore::Node &
300 0 : ForeverStackStore::get_root () const
301 : {
302 0 : return root;
303 : }
304 :
305 : tl::optional<ForeverStackStore::Node &>
306 0 : ForeverStackStore::get_node (NodeId node_id)
307 : {
308 0 : return root.dfs_node (node_id);
309 : }
310 :
311 : tl::optional<const ForeverStackStore::Node &>
312 0 : ForeverStackStore::get_node (NodeId node_id) const
313 : {
314 0 : return root.dfs_node (node_id);
315 : }
316 :
317 : } // namespace Resolver2_0
318 : } // namespace Rust
|