instruct 0.1.0

A language to write general purpose 'makefile like' tasks which are powerful and reuseable
Documentation
use anyhow::Context;

use crate::interpreter::context::ContextRef;
use crate::interpreter::stack::StackRef;
use crate::interpreter::variables::Variables;
use crate::parse::ast::{Executeable, ExecuteableType};

use super::{get_executor, DynExecutor, Executor, ExecutorError, Stack};

struct Executors {
    calle: DynExecutor,
    stack: StackRef,
}

pub struct CallExecutor {
    variables: Variables,
    target_name: String,
    executors: Option<Executors>,
}

impl CallExecutor {
    pub fn new(input: Executeable) -> anyhow::Result<Self> {
        if let ExecuteableType::Call { target } = input.executeable_type {
            let exe = CallExecutor {
                variables: Variables::new(input.output_variables),
                target_name: target,
                executors: None,
            };
            Ok(exe)
        } else {
            Err(ExecutorError::WrongExecutorType(input.executeable_type).into())
        }
    }

    pub fn error_context(&self) -> String {
        format!("calling: '{}'", self.target_name)
    }
}

impl Executor for CallExecutor {
    fn init(&mut self, mut stack: StackRef, ctx: ContextRef) -> anyhow::Result<()> {
        let calle_executeable = ctx
            .borrow()
            .root_namespace
            .resolve_name(&self.target_name)
            .with_context(|| self.error_context())?
            .clone();
        let mut calle_executor =
            get_executor(calle_executeable, stack.clone()).with_context(|| self.error_context())?;

        let mut child_stack: StackRef = Stack::inherit_new(&stack).into();

        calle_executor.init(child_stack.clone(), ctx.clone())?;

        self.variables
            .allocate_and_check_all(&mut stack, &mut child_stack)?;
        self.executors = Some(Executors {
            calle: calle_executor,
            stack: child_stack,
        });

        Ok(())
    }

    fn execute(&mut self, mut parent_stack: StackRef, ctx: ContextRef) -> anyhow::Result<()> {
        if let Some(mut executors) = self.executors.take() {
            executors
                .calle
                .execute(executors.stack.clone(), ctx.clone())
                .with_context(|| self.error_context())?;

            self.variables
                .carry_over(&mut parent_stack, &mut executors.stack)?;

            Ok(())
        } else {
            Err(ExecutorError::NotInitialized.into())
        }
    }
}