aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/resolve/rust-forever-stack.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/resolve/rust-forever-stack.cc')
-rw-r--r--gcc/rust/resolve/rust-forever-stack.cc318
1 files changed, 318 insertions, 0 deletions
diff --git a/gcc/rust/resolve/rust-forever-stack.cc b/gcc/rust/resolve/rust-forever-stack.cc
new file mode 100644
index 0000000..725ae0e
--- /dev/null
+++ b/gcc/rust/resolve/rust-forever-stack.cc
@@ -0,0 +1,318 @@
+// Copyright (C) 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/>.
+
+#include "expected.h"
+#include "rust-ast.h"
+#include "rust-diagnostics.h"
+#include "rust-forever-stack.h"
+#include "rust-rib.h"
+#include "optional.h"
+
+namespace Rust {
+namespace Resolver2_0 {
+
+bool
+ForeverStackStore::Node::is_root () const
+{
+ return !parent.has_value ();
+}
+
+bool
+ForeverStackStore::Node::is_leaf () const
+{
+ return children.empty ();
+}
+
+NodeId
+ForeverStackStore::Node::get_id () const
+{
+ return id;
+}
+
+ForeverStackStore::Node &
+ForeverStackStore::Node::insert_child (NodeId id, tl::optional<Identifier> path,
+ Rib::Kind kind)
+{
+ auto res = children.insert ({Link (id, path), Node (kind, id, *this)});
+
+ rust_debug ("inserting link: Link(%d [%s]): existed? %s", id,
+ path.has_value () ? path.value ().as_string ().c_str ()
+ : "<anon>",
+ !res.second ? "yes" : "no");
+
+ // sanity check on rib kind
+ // pick the value rib, since all ribs should have the same kind anyways
+ rust_assert (res.second || res.first->second.value_rib.kind == kind);
+
+ // verify, if we're using an existing node, our paths don't contradict
+ if (!res.second && path.has_value ())
+ {
+ auto other_path = res.first->first.path;
+ rust_assert (!other_path.has_value ()
+ || other_path.value ().as_string ()
+ == path.value ().as_string ());
+ }
+
+ return res.first->second;
+}
+
+tl::optional<ForeverStackStore::Node &>
+ForeverStackStore::Node::get_child (const Identifier &path)
+{
+ for (auto &ent : children)
+ {
+ if (ent.first.path.has_value ()
+ && ent.first.path->as_string () == path.as_string ())
+ return ent.second;
+ }
+ return tl::nullopt;
+}
+
+tl::optional<const ForeverStackStore::Node &>
+ForeverStackStore::Node::get_child (const Identifier &path) const
+{
+ for (auto &ent : children)
+ {
+ if (ent.first.path.has_value ()
+ && ent.first.path->as_string () == path.as_string ())
+ return ent.second;
+ }
+ return tl::nullopt;
+}
+
+tl::optional<ForeverStackStore::Node &>
+ForeverStackStore::Node::get_parent ()
+{
+ return parent;
+}
+
+tl::optional<const ForeverStackStore::Node &>
+ForeverStackStore::Node::get_parent () const
+{
+ if (parent)
+ return *parent;
+ return tl::nullopt;
+}
+
+tl::optional<const Identifier &>
+ForeverStackStore::Node::get_parent_path () const
+{
+ if (parent.has_value ())
+ for (auto &ent : parent->children)
+ if (ent.first.id == id && ent.first.path.has_value ())
+ return ent.first.path.value ();
+ return tl::nullopt;
+}
+
+Rib &
+ForeverStackStore::Node::get_rib (Namespace ns)
+{
+ switch (ns)
+ {
+ case Namespace::Values:
+ return value_rib;
+ case Namespace::Types:
+ return type_rib;
+ case Namespace::Labels:
+ return label_rib;
+ case Namespace::Macros:
+ return macro_rib;
+ default:
+ rust_unreachable ();
+ }
+}
+
+const Rib &
+ForeverStackStore::Node::get_rib (Namespace ns) const
+{
+ switch (ns)
+ {
+ case Namespace::Values:
+ return value_rib;
+ case Namespace::Types:
+ return type_rib;
+ case Namespace::Labels:
+ return label_rib;
+ case Namespace::Macros:
+ return macro_rib;
+ default:
+ rust_unreachable ();
+ }
+}
+
+tl::expected<NodeId, DuplicateNameError>
+ForeverStackStore::Node::insert (const Identifier &name, NodeId node,
+ Namespace ns)
+{
+ // So what do we do here - if the Rib has already been pushed in an earlier
+ // pass, we might end up in a situation where it is okay to re-add new names.
+ // Do we just ignore that here? Do we keep track of if the Rib is new or not?
+ // should our cursor have info on the current node like "is it newly pushed"?
+ return get_rib (ns).insert (name.as_string (),
+ Rib::Definition::NonShadowable (node));
+}
+
+tl::expected<NodeId, DuplicateNameError>
+ForeverStackStore::Node::insert_shadowable (const Identifier &name, NodeId node,
+ Namespace ns)
+{
+ return get_rib (ns).insert (name.as_string (),
+ Rib::Definition::Shadowable (node));
+}
+
+tl::expected<NodeId, DuplicateNameError>
+ForeverStackStore::Node::insert_globbed (const Identifier &name, NodeId node,
+ Namespace ns)
+{
+ return get_rib (ns).insert (name.as_string (),
+ Rib::Definition::Globbed (node));
+}
+
+void
+ForeverStackStore::Node::reverse_iter (std::function<KeepGoing (Node &)> lambda)
+{
+ for (Node *tmp = this; lambda (*tmp) == KeepGoing::Yes && !tmp->is_root ();
+ tmp = &tmp->parent.value ())
+ ;
+}
+
+void
+ForeverStackStore::Node::reverse_iter (
+ std::function<KeepGoing (const Node &)> lambda) const
+{
+ for (const Node *tmp = this;
+ lambda (*tmp) == KeepGoing::Yes && !tmp->is_root ();
+ tmp = &tmp->parent.value ())
+ ;
+}
+
+void
+ForeverStackStore::Node::child_iter (
+ std::function<KeepGoing (NodeId, tl::optional<const Identifier &>, Node &)>
+ lambda)
+{
+ for (auto &ent : children)
+ {
+ tl::optional<const Identifier &> path;
+ if (ent.first.path.has_value ())
+ path = ent.first.path.value ();
+ auto keep_going = lambda (ent.first.id, path, ent.second);
+ if (keep_going == KeepGoing::No)
+ return;
+ }
+}
+
+void
+ForeverStackStore::Node::child_iter (
+ std::function<KeepGoing (NodeId, tl::optional<const Identifier &>,
+ const Node &)>
+ lambda) const
+{
+ for (auto &ent : children)
+ {
+ tl::optional<const Identifier &> path;
+ if (ent.first.path.has_value ())
+ path = ent.first.path.value ();
+ auto keep_going = lambda (ent.first.id, path, ent.second);
+ if (keep_going == KeepGoing::No)
+ return;
+ }
+}
+
+ForeverStackStore::Node &
+ForeverStackStore::Node::find_closest_module ()
+{
+ // get kind of value_rib
+ // but all ribs should share the same kind anyways
+ if (value_rib.kind == Rib::Kind::Module || !parent.has_value ())
+ return *this;
+ else
+ return parent->find_closest_module ();
+}
+
+const ForeverStackStore::Node &
+ForeverStackStore::Node::find_closest_module () const
+{
+ // get kind of value_rib
+ // but all ribs should share the same kind anyways
+ if (value_rib.kind != Rib::Kind::Module || !parent.has_value ())
+ return *this;
+ else
+ return parent->find_closest_module ();
+}
+
+tl::optional<ForeverStackStore::Node &>
+ForeverStackStore::Node::dfs_node (NodeId to_find)
+{
+ if (id == to_find)
+ return *this;
+
+ for (auto &child : children)
+ {
+ auto candidate = child.second.dfs_node (to_find);
+
+ if (candidate.has_value ())
+ return candidate;
+ }
+
+ return tl::nullopt;
+}
+
+tl::optional<const ForeverStackStore::Node &>
+ForeverStackStore::Node::dfs_node (NodeId to_find) const
+{
+ if (id == to_find)
+ return *this;
+
+ for (auto &child : children)
+ {
+ auto candidate = child.second.dfs_node (to_find);
+
+ if (candidate.has_value ())
+ return candidate;
+ }
+
+ return tl::nullopt;
+}
+
+ForeverStackStore::Node &
+ForeverStackStore::get_root ()
+{
+ return root;
+}
+
+const ForeverStackStore::Node &
+ForeverStackStore::get_root () const
+{
+ return root;
+}
+
+tl::optional<ForeverStackStore::Node &>
+ForeverStackStore::get_node (NodeId node_id)
+{
+ return root.dfs_node (node_id);
+}
+
+tl::optional<const ForeverStackStore::Node &>
+ForeverStackStore::get_node (NodeId node_id) const
+{
+ return root.dfs_node (node_id);
+}
+
+} // namespace Resolver2_0
+} // namespace Rust