use crate::engine::Engine;
use crate::static_args::NodeInstance;
use crate::{Diagnostic, Level, Span};
use comemo::TrackedMut;
use rustre_parser::ast::{AstNode, AstToken, NodeNode, NodeProfileNode, ParamsNode};
#[memoize]
pub fn check_arity(mut engine: TrackedMut<Engine>, node: NodeNode) {
if crate::stdlib::is_iterator(TrackedMut::reborrow_mut(&mut engine), node.clone()) {
return;
}
let sig = crate::get_signature(
TrackedMut::reborrow_mut(&mut engine),
NodeInstance::new_non_parametric(node.clone()),
);
let get_span = |f: fn(&NodeProfileNode) -> Option<ParamsNode>| {
node.node_profile_node()
.map(|profile| {
f(&profile)
.map(|params| Span::of_node(params.syntax()))
.unwrap_or_else(|| Span::of_node(profile.syntax()))
})
.unwrap_or_else(|| Span::of_node(node.syntax()))
};
let node_kind_str = if node.is_function() {
"function"
} else {
"node"
};
if sig.params.is_empty() {
let name = sig.name.as_ref().map(|i| i.text()).unwrap_or_default();
let span = get_span(NodeProfileNode::params);
Diagnostic::build(Level::Error, format!("node {:?} takes no parameter", name))
.with_attachment(span, "nodes must take at least 1 parameter")
.with_help(format!("add a dummy parameter to this {node_kind_str}"))
.emit(&mut engine);
}
if sig.return_params.is_empty() {
let name = sig.name.as_ref().map(|i| i.text()).unwrap_or_default();
let span = get_span(NodeProfileNode::return_params);
Diagnostic::build(Level::Error, format!("node {:?} returns nothing", name))
.with_attachment(span, "nodes must return at least 1 value")
.with_help(format!("add a dummy parameter to this {node_kind_str}"))
.emit(&mut engine);
}
}