diff options
Diffstat (limited to 'gcc/rust/resolve/rust-forever-stack.cc')
-rw-r--r-- | gcc/rust/resolve/rust-forever-stack.cc | 318 |
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 |