use core::fmt;
use crate::alloc::string::ToString;
use crate::ast::{AstGraph, AstNode};
use crate::NodeId;
use alloc::format;
use alloc::string::String;
use alloc::vec::Vec;
pub type AstNodeAndId<'a> = (&'a AstNode, NodeId);
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum NodeResolutionError {
Error(String),
NodeNotFound(String),
}
impl fmt::Display for NodeResolutionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Error(msg) => f.write_str(msg),
Self::NodeNotFound(node) => {
f.write_str(&format!("The node {node} is not in the graph"))
}
}
}
}
pub fn ensure_node(graph: &AstGraph, nid: NodeId) -> Result<AstNodeAndId<'_>, NodeResolutionError> {
graph.nodes.get(&nid).map_or_else(
|| Err(NodeResolutionError::NodeNotFound(nid.0.to_string())),
|n| Ok((n, nid)),
)
}
pub fn ensure_only_one_child<'a>(
graph: &'a AstGraph,
node: &AstNode,
) -> Result<AstNodeAndId<'a>, NodeResolutionError> {
let [child_id] = node.children.as_slice() else {
return Err(NodeResolutionError::Error(format!(
"A {} must have exactly one child, found {}",
node.kind,
node.children.len()
)));
};
ensure_node(graph, *child_id)
}
pub fn children<'a>(
graph: &'a AstGraph,
node: &AstNode,
) -> Result<Vec<AstNodeAndId<'a>>, NodeResolutionError> {
node.children
.iter()
.map(|child_id| ensure_node(graph, *child_id))
.collect()
}
pub fn ensure_only_two_children<'a>(
graph: &'a AstGraph,
node: &AstNode,
) -> Result<(AstNodeAndId<'a>, AstNodeAndId<'a>), NodeResolutionError> {
let [child_1, child_2] = node.children.as_slice() else {
return Err(NodeResolutionError::Error(format!(
"A {} must have exactly two children, found {}",
node.kind,
node.children.len()
)));
};
ensure_node(graph, *child_1).and_then(|c1| ensure_node(graph, *child_2).map(|c2| (c1, c2)))
}