use std::sync::Arc;
use hamelin_eval::{eval, Environment};
use hamelin_lib::{
err::{TranslationError, TranslationErrors},
func::def::ParameterBinding,
tree::{
ast::identifier::ParsedSimpleIdentifier,
typed_ast::expression::{
ExpressionAlgebra, TypedApply, TypedArrayLiteral, TypedBroadcastApply, TypedCast,
TypedErrorExpression, TypedExpression, TypedFieldLookup, TypedFieldReference,
TypedLambda, TypedStructLiteral, TypedTsTrunc, TypedTupleLiteral,
TypedVariantIndexAccess,
},
},
};
type FreezeResult = Result<Arc<TypedExpression>, TranslationErrors>;
pub struct FreezeAlgebra;
impl FreezeAlgebra {
fn try_eval(expr: &TypedExpression) -> FreezeResult {
let env = Environment::default();
match eval(expr, &env) {
Ok(value) => Ok(value.into()),
Err(e) if e.is_unfoldable() => Ok(Arc::new(expr.clone())),
Err(e) => Err(TranslationError::wrap(expr, e).single()),
}
}
}
impl ExpressionAlgebra<FreezeResult> for FreezeAlgebra {
fn apply(
&mut self,
node: &TypedApply,
expr: &TypedExpression,
children: ParameterBinding<FreezeResult>,
) -> FreezeResult {
let new_children = children.try_map(|r| r)?;
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.try_map(|r| r)?;
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 = children.into_iter().collect::<Result<Vec<_>, _>>()?;
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 = children.into_iter().collect::<Result<Vec<_>, _>>()?;
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 = children
.into_iter()
.map(|(name, r)| r.map(|expr| (name, expr)))
.collect::<Result<Vec<_>, _>>()?;
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, child?);
Self::try_eval(&rebuilt)
}
fn field_lookup(
&mut self,
node: &TypedFieldLookup,
expr: &TypedExpression,
child: FreezeResult,
) -> FreezeResult {
let rebuilt = node.replace_children(expr, child?);
Self::try_eval(&rebuilt)
}
fn cast(
&mut self,
node: &TypedCast,
expr: &TypedExpression,
child: FreezeResult,
) -> FreezeResult {
let rebuilt = node.replace_children(expr, child?);
Self::try_eval(&rebuilt)
}
fn ts_trunc(
&mut self,
node: &TypedTsTrunc,
expr: &TypedExpression,
child: FreezeResult,
) -> FreezeResult {
let rebuilt = node.replace_children(expr, child?);
Self::try_eval(&rebuilt)
}
fn lambda(
&mut self,
node: &TypedLambda,
expr: &TypedExpression,
body: FreezeResult,
) -> FreezeResult {
let rebuilt = node.replace_children(expr, body?);
Self::try_eval(&rebuilt)
}
fn field_reference(
&mut self,
_node: &TypedFieldReference,
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 {
Ok(Arc::new(expr.clone()))
}
}