hamelin_translation 0.4.3

Lowering and IR for Hamelin query language
Documentation
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,
        },
    },
};

/// Result type for freeze: either a fully-evaluated Value or a partially-simplified expression.
type FreezeResult = Result<Value, Arc<TypedExpression>>;

/// Algebra for freezing expressions via catamorphism.
pub struct FreezeAlgebra;

impl FreezeAlgebra {
    /// Try to evaluate the expression. If successful, return Ok(value).
    /// If evaluation fails, return Err with the expression.
    fn try_eval(expr: &TypedExpression) -> FreezeResult {
        let env = Environment::default();
        eval(expr, &env).map_err(|_| Arc::new(expr.clone()))
    }

    /// Convert a FreezeResult back to an expression.
    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()))
    }
}