use crate::node;
use std::fmt;
use thiserror::Error;
#[derive(Debug, Error)]
#[error("too many connections ({0}), max is {max}", max = node::Conns::MAX)]
pub struct TooManyConns(pub usize);
#[derive(Debug, Error)]
#[error("edge references invalid output index {index} (node has {n_outputs} outputs)")]
pub struct InvalidOutputIndex {
pub index: usize,
pub n_outputs: usize,
}
#[derive(Debug, Error)]
#[error("nested graph not found at path {0:?}")]
pub struct NestedGraphNotFound(pub Vec<node::Id>);
#[derive(Debug)]
pub struct NodeExprError {
pub path: Vec<node::Id>,
pub error: node::ExprError,
}
#[derive(Debug, Error)]
pub enum NodeFnError {
#[error(transparent)]
NestedGraphNotFound(#[from] NestedGraphNotFound),
#[error(transparent)]
Expr(#[from] NodeExprError),
}
#[derive(Debug)]
pub struct NodeFnErrors(pub Vec<NodeFnError>);
#[derive(Debug, Error)]
pub enum NodeConnsError {
#[error(transparent)]
TooManyConns(#[from] TooManyConns),
#[error(transparent)]
InvalidOutputIndex(#[from] InvalidOutputIndex),
}
#[derive(Debug)]
pub struct MetaError {
pub path: Vec<node::Id>,
pub error: NodeConnsError,
}
#[derive(Debug)]
pub struct MetaErrors(pub Vec<MetaError>);
#[derive(Debug, Error)]
pub enum LowerError {
#[error("connection error{}", at_node(node))]
Conns {
node: Option<node::Id>,
#[source]
error: NodeConnsError,
},
#[error(
"branch {branch}: node {node} is conditional on an arm but depends on \
unevaluated work outside the branch region"
)]
Entangled { branch: node::Id, node: node::Id },
#[error("node {node} input {input}: unsupported mix of input sources")]
MixedInputSources { node: node::Id, input: usize },
#[error(
"internal: output {output} of node {node} unavailable resolving an input of {consumer}"
)]
Unresolved {
node: node::Id,
output: usize,
consumer: node::Id,
},
}
#[derive(Debug, Error)]
pub enum ModuleError {
#[error("connection error at {}", level(path))]
NodeConns {
path: Vec<node::Id>,
#[source]
error: NodeConnsError,
},
#[error("failed to lower {}", level(path))]
Lower {
path: Vec<node::Id>,
#[source]
error: LowerError,
},
#[error(transparent)]
NestedGraphNotFound(#[from] NestedGraphNotFound),
#[error(transparent)]
MetaErrors(#[from] MetaErrors),
#[error(transparent)]
NodeFnErrors(#[from] NodeFnErrors),
#[error("internal compiler error: invalid IR for {}: {detail}", level(path))]
InvalidIr { path: Vec<node::Id>, detail: String },
}
impl fmt::Display for MetaError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"node-{}: {}",
super::names::path_string(&self.path),
self.error
)
}
}
impl fmt::Display for MetaErrors {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, err) in self.0.iter().enumerate() {
if i > 0 {
writeln!(f)?;
}
write!(f, "{err}")?;
}
Ok(())
}
}
impl fmt::Display for NodeExprError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"node-{}: {}",
super::names::path_string(&self.path),
self.error
)
}
}
impl fmt::Display for NodeFnErrors {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, err) in self.0.iter().enumerate() {
if i > 0 {
writeln!(f)?;
}
write!(f, "{err}")?;
}
Ok(())
}
}
impl std::error::Error for MetaError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.error)
}
}
impl std::error::Error for MetaErrors {}
impl std::error::Error for NodeExprError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.error)
}
}
impl std::error::Error for NodeFnErrors {}
fn level(path: &[node::Id]) -> String {
if path.is_empty() {
"the root level".to_string()
} else {
format!("level {}", super::names::path_string(path))
}
}
fn at_node(node: &Option<node::Id>) -> String {
node.map(|n| format!(" at node {n}")).unwrap_or_default()
}