alduin 0.0.1

WIP: A toy compiler backend
Documentation
use std::{
    collections::HashMap,
    sync::{Arc, Mutex},
};

use crate::{
    compiler::compiled_code::CompiledCode,
    compiler::{compiled_code::Symbol, graph::Graph, Compiler},
};

use super::registry::VM_REGISTRY;

pub struct VirtualMachine {
    pub(crate) registry_index: usize,
    pub(crate) compiler: Compiler,
    uncompiled_functions: Mutex<HashMap<Symbol, Box<Graph>>>,
    symbol_resolver: Mutex<Option<Box<dyn Fn(&Symbol) + Sync + Send>>>,
}

impl VirtualMachine {
    pub fn new() -> Arc<Self> {
        crate::init_logger();
        VM_REGISTRY.add(Self {
            registry_index: 0,
            compiler: Compiler::new(),
            uncompiled_functions: Mutex::new(HashMap::new()),
            symbol_resolver: Mutex::new(None),
        })
    }

    pub fn set_symbol_resolver(&self, resolver: Box<dyn Fn(&Symbol) + Sync + Send>) {
        *self.symbol_resolver.lock().unwrap() = Some(resolver);
    }

    pub fn contains(&self, name: &Symbol) -> bool {
        if self.uncompiled_functions.lock().unwrap().contains_key(name) {
            return true;
        }
        self.compiler.contains(name)
    }

    pub fn add(&self, name: Symbol, graph: Box<Graph>) {
        self.uncompiled_functions
            .lock()
            .unwrap()
            .insert(name, graph);
    }

    fn compile(&self, name: &Symbol) {
        let mut uncompiled_functions = self.uncompiled_functions.lock().unwrap();
        if let Some(graph) = uncompiled_functions.remove(name) {
            std::mem::drop(uncompiled_functions);
            self.compiler.compile(name.to_owned(), graph);
        }
    }

    /// Resolve and compile a function
    pub fn resolve(&self, name: &Symbol) -> Arc<dyn CompiledCode> {
        if !self.compiler.contains(name) {
            let resolver = self.symbol_resolver.lock().unwrap();
            if let Some(f) = resolver.as_ref() {
                f(name);
            }
        }
        self.compile(name);
        self.compiler.get(name)
    }

    pub fn get_instance_by_code_interior_pointer(ptr: *const u8) -> Option<Arc<Self>> {
        VM_REGISTRY.get_vm_by_code_interior_pointer(ptr)
    }

    pub fn get_compiled_code_by_code_interior_pointer(
        &self,
        ptr: *const u8,
    ) -> Option<&dyn CompiledCode> {
        self.compiler.code.get_code_by_interior_pointer(ptr)
    }
}