gluon_vm 0.18.3

The virtual machine for executing the gluon programming language
Documentation
use crate::base::{
    ast::{self, Expr, ExprField, Pattern, TypeBinding, TypedIdent, ValueBinding},
    pos,
    symbol::{Symbol, Symbols},
    types::{KindedIdent, Type, TypeContext, remove_forall, row_iter},
};

use crate::macros::Error;

use crate::derive::*;

pub fn generate<'ast>(
    mut arena: ast::ArenaRef<'_, 'ast, Symbol>,
    symbols: &mut Symbols,
    bind: &TypeBinding<'ast, Symbol>,
) -> Result<ValueBinding<'ast, Symbol>, Error> {
    let span = bind.name.span;

    let deserializer_fn = TypedIdent::new(symbols.simple_symbol("deserializer"));

    let field_deserialize = symbols.simple_symbol("field");
    let deserializer_ident = {
        let id = symbols.simple_symbol("deserializer");
        move || ident(span, id.clone())
    };

    let mut self_type = {
        let mut arena = arena;
        move || bind.alias.value.self_type(&mut arena)
    };

    let deserializer_expr = match **remove_forall(bind.alias.value.unresolved_type()) {
        Type::Record(ref row) => {
            let field_symbols: Vec<_> = row_iter(row)
                .map(|field| {
                    TypedIdent::new(Symbol::from(format!("{}", field.name.declared_name())))
                })
                .collect();

            arena.sequence_actions(
                symbols,
                span,
                &field_symbols,
                pos::spanned(
                    span,
                    Expr::Record {
                        exprs: arena.alloc_extend(field_symbols.iter().map(|id| ExprField {
                            name: pos::spanned(span, id.name.clone()),
                            value: None,
                            metadata: Default::default(),
                        })),
                        types: &mut [],
                        typ: Type::hole(),
                        base: None,
                    },
                ),
                &mut |field| {
                    arena.app(
                        span,
                        field_deserialize.clone(),
                        vec![literal(span, field.declared_name()), deserializer_ident()],
                    )
                },
            )
        }
        Type::Variant(ref row) => row_iter(row)
            .fold(None, |acc, variant| {
                let deserialize_variant = arena.app(
                    span,
                    symbols.simple_symbol("map"),
                    vec![
                        ident(variant.name.span, variant.name.value.clone()),
                        deserializer_ident(),
                    ],
                );
                Some(match acc {
                    Some(prev) => arena.infix(
                        span,
                        prev,
                        symbols.simple_symbol("<|>"),
                        deserialize_variant,
                    ),
                    None => deserialize_variant,
                })
            })
            .unwrap(),
        _ => return Err(Error::message("Unable to derive Deserialize for this type")),
    };

    let serialization_import = arena.generate_import_(
        span,
        symbols,
        &["ValueDeserializer"],
        &["deserializer", "field"],
        true,
        "std.json.de",
    );
    let functor_import = arena.generate_import(span, symbols, &[], &["map"], "std.functor");
    let applicative_import = arena.generate_import(span, symbols, &[], &["<*>"], "std.applicative");
    let alternative_import = arena.generate_import(span, symbols, &[], &["<|>"], "std.alternative");

    let deserializer_binding = ValueBinding {
        name: pos::spanned(span, Pattern::Ident(deserializer_fn.clone())),
        args: &mut [],
        expr: deserializer_expr,
        metadata: Default::default(),
        typ: Some(TypeContext::app(
            &mut arena.clone(),
            arena.ident(KindedIdent::new(symbols.simple_symbol("ValueDeserializer"))),
            arena.clone().alloc_extend(Some(self_type())),
        )),
        resolved_type: Type::hole(),
    };

    let export_record_expr = pos::spanned(
        span,
        Expr::Record {
            typ: Type::hole(),
            types: &mut [],
            exprs: arena.alloc_extend(vec![ExprField {
                metadata: Default::default(),
                name: pos::spanned(span, symbols.simple_symbol("deserializer")),
                value: Some(ident(span, deserializer_fn.name.clone())),
            }]),
            base: None,
        },
    );

    let deserializer_record_expr = vec![
        serialization_import,
        functor_import,
        applicative_import,
        alternative_import,
        deserializer_binding,
    ]
    .into_iter()
    .rev()
    .fold(export_record_expr, |expr, bind| {
        pos::spanned(span, Expr::let_binding(arena, bind, expr))
    });

    Ok(ValueBinding {
        name: pos::spanned(
            span,
            Pattern::Ident(TypedIdent::new(symbols.simple_symbol(format!(
                "deserialize_{}",
                bind.alias.value.name.declared_name()
            )))),
        ),
        args: &mut [],
        expr: deserializer_record_expr,
        metadata: Default::default(),
        typ: Some(binding_type(
            arena,
            symbols,
            span,
            "Deserialize",
            self_type(),
            bind,
        )),
        resolved_type: Type::hole(),
    })
}