use std::sync::Arc;
use hamelin_eval::value::Value;
use hamelin_eval::{eval, Environment};
use hamelin_lib::{
func::def::ParameterBinding,
tree::{
ast::identifier::ParsedSimpleIdentifier,
typed_ast::expression::{
ExpressionAlgebra, TypedApply, TypedArrayLiteral, TypedBroadcastApply, TypedCast,
TypedColumnReference, TypedErrorExpression, TypedExpression, TypedFieldLookup,
TypedLambda, TypedStructLiteral, TypedTsTrunc, TypedTupleLiteral,
TypedVariantIndexAccess,
},
},
};
type FreezeResult = Result<Value, Arc<TypedExpression>>;
pub struct FreezeAlgebra;
impl FreezeAlgebra {
fn try_eval(expr: &TypedExpression) -> FreezeResult {
let env = Environment::default();
eval(expr, &env).map_err(|_| Arc::new(expr.clone()))
}
fn to_expr(result: FreezeResult) -> Arc<TypedExpression> {
match result {
Ok(value) => value.into(),
Err(expr) => expr,
}
}
}
impl ExpressionAlgebra<FreezeResult> for FreezeAlgebra {
fn apply(
&mut self,
node: &TypedApply,
expr: &TypedExpression,
children: ParameterBinding<FreezeResult>,
) -> FreezeResult {
let new_children = children.map(Self::to_expr);
let rebuilt = node.replace_children(expr, new_children);
Self::try_eval(&rebuilt)
}
fn broadcast_apply(
&mut self,
node: &TypedBroadcastApply,
expr: &TypedExpression,
children: ParameterBinding<FreezeResult>,
) -> FreezeResult {
let new_children = children.map(Self::to_expr);
let rebuilt = node.replace_children(expr, new_children);
Self::try_eval(&rebuilt)
}
fn array_literal(
&mut self,
node: &TypedArrayLiteral,
expr: &TypedExpression,
children: Vec<FreezeResult>,
) -> FreezeResult {
let new_children: Vec<_> = children.into_iter().map(Self::to_expr).collect();
let rebuilt = node.replace_children(expr, new_children);
Self::try_eval(&rebuilt)
}
fn tuple_literal(
&mut self,
node: &TypedTupleLiteral,
expr: &TypedExpression,
children: Vec<FreezeResult>,
) -> FreezeResult {
let new_children: Vec<_> = children.into_iter().map(Self::to_expr).collect();
let rebuilt = node.replace_children(expr, new_children);
Self::try_eval(&rebuilt)
}
fn struct_literal(
&mut self,
node: &TypedStructLiteral,
expr: &TypedExpression,
children: Vec<(ParsedSimpleIdentifier, FreezeResult)>,
) -> FreezeResult {
let new_children: Vec<_> = children
.into_iter()
.map(|(name, r)| (name, Self::to_expr(r)))
.collect();
let rebuilt = node.replace_children(expr, new_children);
Self::try_eval(&rebuilt)
}
fn variant_index_access(
&mut self,
node: &TypedVariantIndexAccess,
expr: &TypedExpression,
child: FreezeResult,
) -> FreezeResult {
let rebuilt = node.replace_children(expr, Self::to_expr(child));
Self::try_eval(&rebuilt)
}
fn field_lookup(
&mut self,
node: &TypedFieldLookup,
expr: &TypedExpression,
child: FreezeResult,
) -> FreezeResult {
let rebuilt = node.replace_children(expr, Self::to_expr(child));
Self::try_eval(&rebuilt)
}
fn cast(
&mut self,
node: &TypedCast,
expr: &TypedExpression,
child: FreezeResult,
) -> FreezeResult {
let rebuilt = node.replace_children(expr, Self::to_expr(child));
Self::try_eval(&rebuilt)
}
fn ts_trunc(
&mut self,
node: &TypedTsTrunc,
expr: &TypedExpression,
child: FreezeResult,
) -> FreezeResult {
let rebuilt = node.replace_children(expr, Self::to_expr(child));
Self::try_eval(&rebuilt)
}
fn lambda(
&mut self,
node: &TypedLambda,
expr: &TypedExpression,
body: FreezeResult,
) -> FreezeResult {
let rebuilt = node.replace_children(expr, Self::to_expr(body));
Self::try_eval(&rebuilt)
}
fn column_reference(
&mut self,
_node: &TypedColumnReference,
expr: &TypedExpression,
) -> FreezeResult {
Self::try_eval(expr)
}
fn leaf(&mut self, expr: &TypedExpression) -> FreezeResult {
Self::try_eval(expr)
}
fn error(&mut self, _node: &TypedErrorExpression, expr: &TypedExpression) -> FreezeResult {
Err(Arc::new(expr.clone()))
}
}