Branch data Line data Source code
1 : : // Copyright (C) 2024 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
|