alpaca_ir 0.0.0

AlpacaIR is a intermediate represenation meant to make making compilers easier.
Documentation
pub mod stage1;
pub mod stage2;

use std::any::Any;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

use crate::error::ErrorSection;
use crate::exit;

#[derive(Debug)]
pub struct AlpacaPipelineInfo {
    data: HashMap<&'static str, Box<dyn Any>>,
}

impl AlpacaPipelineInfo {
    pub fn new() -> Self {
        Self { data: HashMap::new() }
    }
    
    pub fn add_data<T: 'static>(&mut self, key: &'static str, value: T) {
        if self.data.contains_key(key) {
            log::error!("key already exists!");
            exit!(ErrorSection::Pipeline, 13474);
        }
        
        self.data.insert(key, Box::new(value));
    }
    
    pub fn get_data_ref<T: 'static>(&self, key: &'static str) -> Option<&T> {
        self.data.get(key)?.downcast_ref::<T>()
    }
    
    pub fn get_data_mut<T: 'static>(&mut self, key: &'static str) -> Option<&mut T> {
        self.data.get_mut(key)?.downcast_mut::<T>()
    }
    
    pub fn remove_data(&mut self, key: &str) { self.data.remove(key); }
}

pub trait CriaPipelineModule {
    fn build(&self, pipeline: &mut AlpacaPipeline);
}

pub struct AlpacaPipeline {
    info: Rc<RefCell<AlpacaPipelineInfo>>,
    passes: Vec<Box<dyn Fn(Rc<RefCell<AlpacaPipelineInfo>>) -> u32>>,
}

impl Default for AlpacaPipeline {
    fn default() -> Self {
        env_logger::init();
        Self { info: Rc::new(RefCell::new(AlpacaPipelineInfo::new())), passes: Vec::new() }
    }
}

impl AlpacaPipeline {
    pub fn add_pass<F>(&mut self, pass: F) -> &mut Self
    where
        F: Fn(Rc<RefCell<AlpacaPipelineInfo>>) -> u32 + 'static,
    {
        self.passes.push(Box::new(pass));
        self
    }
    
    pub fn add_modules(&mut self, modules: &[&dyn CriaPipelineModule]) -> &mut Self {
        for module in modules {
            module.build(self);
        }
        
        self
    }
    
    pub fn run(&mut self) {
        for pass in &mut self.passes {
            let exit_code = pass(self.info.clone());
            if exit_code != 0 {
                exit!(ErrorSection::Pipeline, exit_code);
            }
        }
    }
}