instruct 0.1.0

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

use crate::interpreter::stack::Stack;
use crate::parse::ast::{Executeable, ExecuteableType};

use self::block::BlockExecutor;
use self::call::CallExecutor;
use self::command::CommandExecutor;
use self::task::TaskExecutor;

use super::context::ContextRef;
use super::stack::StackRef;

mod block;
mod call;
mod command;
mod task;

#[derive(Error, Debug)]
pub enum ExecutorError {
    #[error("Tried to create executor with wrong executor type {0:?}, this should not happen!")]
    WrongExecutorType(ExecuteableType),
    #[error("Executor for type {0:?} not yet implemented!")]
    NotImplemented(ExecuteableType),
    #[error("Executor was not initialized")]
    NotInitialized,
}

pub trait Executor {
    fn init(&mut self, stack: StackRef, ctx: ContextRef) -> anyhow::Result<()>;

    fn execute(&mut self, stack: StackRef, ctx: ContextRef) -> anyhow::Result<()>;
}

type DynExecutor = Box<dyn Executor>;

#[allow(unreachable_patterns)]
pub fn get_executor(input: Executeable, _stack: StackRef) -> anyhow::Result<DynExecutor> {
    match &input.executeable_type {
        ExecuteableType::Command { .. } => Ok(Box::new(CommandExecutor::new(input)?)),
        ExecuteableType::Task { .. } => Ok(Box::new(TaskExecutor::new(input)?)),
        ExecuteableType::Block { .. } => Ok(Box::new(BlockExecutor::new(input)?)),
        ExecuteableType::Call { .. } => Ok(Box::new(CallExecutor::new(input)?)),
        exec_type => Err(ExecutorError::NotImplemented(exec_type.clone()).into()),
    }
}