use std::any::TypeId;
use std::sync::Arc;
use anyhow::bail;
use crate::func::def::{FunctionDef, ParameterBinding, ParameterBindingProvider, Parameters};
use crate::tree::ast::expression::{Expression, ExpressionKind};
use crate::tree::typed_ast::context::ExpressionTranslationContext;
use crate::tree::typed_ast::expression::TypedExpression;
use crate::types::array::Array;
use crate::types::matcher::AnyMatcher;
use crate::types::Type;
#[derive(Default, Clone)]
pub struct Transform;
impl FunctionDef for Transform {
fn name(&self) -> &'static str {
"transform"
}
fn parameters(&self) -> Parameters {
Parameters::new()
.with("array", AnyMatcher)
.with("lambda", AnyMatcher)
}
fn custom_bind(
&self,
ast_binding: &ParameterBinding<Arc<Expression>>,
ctx: &mut ExpressionTranslationContext,
) -> anyhow::Result<Option<ParameterBinding<Arc<TypedExpression>>>> {
let array_ast = ast_binding.get_by_name("array")?.clone();
let typed_array = Arc::new(TypedExpression::from_ast_with_context(array_ast, ctx));
let element_type = match typed_array.resolved_type.as_ref() {
Type::Array(arr) => arr.element_type.clone(),
other => bail!("Expected array type, got {}", other),
};
let lambda_ast = ast_binding.get_by_name("lambda")?.clone();
let ExpressionKind::Lambda(lambda) = &lambda_ast.kind else {
bail!("Expected lambda expression");
};
let lambda_with_hints = lambda.with_param_types(&[element_type])?;
let lambda_expr = Expression {
kind: lambda_with_hints.into(),
span: lambda_ast.span.clone(),
};
let typed_lambda = Arc::new(TypedExpression::from_ast_with_context(
Arc::new(lambda_expr),
ctx,
));
Ok(Some(ParameterBinding::from_named([
("array".to_string(), typed_array),
("lambda".to_string(), typed_lambda),
])))
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
let lambda_arg = bindings.get_by_name("lambda")?;
let return_type = match lambda_arg.typ() {
Type::Function(f) => f.return_type.as_ref().clone(),
Type::Unknown => Type::Unknown,
other => bail!("Expected function type for lambda, got {}", other),
};
Ok(Array::new(return_type).into())
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}