hamelin_translation 0.9.7

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

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

impl FreezeAlgebra {
    /// Try to evaluate the expression. If it evaluates to a value, return that
    /// value as an expression. If it can't be folded (e.g. column reference),
    /// return the original expression. If it's a genuine runtime error (e.g.
    /// division by zero), propagate as TranslationErrors.
    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()))
    }
}