ankha 0.2.3

Ankha scripting toolset
Documentation
use crate::{
    library::{array::Array, option::AnkhaOption, reflection::Function},
    script::stack_managed_variant,
};
use intuicio_core::{
    context::Context,
    registry::Registry,
    transformer::{DynamicManagedValueTransformer, ValueTransformer},
    types::struct_type::NativeStructBuilder,
};
use intuicio_derive::{intuicio_method, intuicio_methods};

pub fn install(registry: &mut Registry) {
    registry.add_type(
        NativeStructBuilder::new_named_uninitialized::<Closure>("Closure")
            .module_name("closure")
            .build(),
    );
    registry.add_function(Closure::new__define_function(registry));
    registry.add_function(Closure::from_function__define_function(registry));
    registry.add_function(Closure::call__define_function(registry));
}

pub struct Closure {
    function: Function,
    captured: Array,
}

#[intuicio_methods(module_name = "closure")]
impl Closure {
    #[intuicio_method(transformer = "DynamicManagedValueTransformer")]
    pub fn new(function: Function, captured: Array) -> Self {
        Self { function, captured }
    }

    #[intuicio_method(transformer = "DynamicManagedValueTransformer")]
    pub fn from_function(function: Function) -> Self {
        Self {
            function,
            captured: Default::default(),
        }
    }

    pub fn invoke(
        &mut self,
        context: &mut Context,
        registry: &Registry,
        arguments: Vec<AnkhaOption>,
    ) {
        for argument in arguments.into_iter().rev() {
            match argument {
                AnkhaOption::None => {
                    panic!("Cannot use none value as closure argument!");
                }
                AnkhaOption::Owned(value) => {
                    context.stack().push(value);
                }
                AnkhaOption::Ref(value) => {
                    context.stack().push(value);
                }
                AnkhaOption::RefMut(value) => {
                    context.stack().push(value);
                }
                AnkhaOption::Lazy(value) => {
                    context.stack().push(value);
                }
                AnkhaOption::Gc(value) => {
                    context.stack().push(value);
                }
            }
        }
        for argument in self.captured.inner_mut().iter_mut().rev() {
            match argument {
                AnkhaOption::None => {
                    panic!("Cannot use none value as closure capture!");
                }
                AnkhaOption::Owned(_) => {
                    panic!("Cannot use owned value as closure capture!");
                }
                AnkhaOption::Ref(value) => {
                    context
                        .stack()
                        .push(value.borrow().expect("Could not borrow ref value!"));
                }
                AnkhaOption::RefMut(value) => {
                    context.stack().push(
                        value
                            .borrow_mut()
                            .expect("Could not borrow mutably ref mut value!"),
                    );
                }
                AnkhaOption::Lazy(value) => {
                    context.stack().push(value.clone());
                }
                AnkhaOption::Gc(value) => {
                    context.stack().push(value.reference());
                }
            }
        }
        self.function.0.invoke(context, registry);
    }

    #[intuicio_method(
        use_context,
        use_registry,
        transformer = "DynamicManagedValueTransformer"
    )]
    pub fn call(
        &mut self,
        context: &mut Context,
        registry: &Registry,
        arguments: Array,
    ) -> AnkhaOption {
        self.invoke(context, registry, arguments.into_inner());
        if self.function.0.signature().outputs.len() == 1 {
            stack_managed_variant(
                context,
                |_, value| value.into(),
                |_, value| value.into(),
                |_, value| value.into(),
                |_, value| value.into(),
                |_, value| value.into(),
            )
        } else {
            AnkhaOption::None
        }
    }
}