ralix 0.2.0

A simple, type-safe, tree walking interpreter
use std::{
    fs, io,
    path::{self, Path, PathBuf},
};

use serde::Serialize;

use crate::{
    DIRECTORY_INDEX_MODULE_NAME, Expression, RALIX_VALID_EXTENSIONS, expressions::Identifier,
    types::Type,
};

#[derive(Clone, Debug, Serialize, PartialEq)]
pub struct Binding {
    pub ident: Identifier,
    pub type_annotation: Option<Type>,
    pub value: Expression,
    pub is_constant: bool,
}

pub fn resolve_file_module_path<P: AsRef<Path>>(
    working_directory_path: P,
    module_names: &[Identifier],
) -> io::Result<(Identifier, PathBuf)> {
    let relative_path = PathBuf::from(&module_names.join(path::MAIN_SEPARATOR_STR));
    let mut path = {
        let wd = working_directory_path.as_ref();
        wd.join(relative_path)
    };
    let mut found = false;

    if path.is_dir() {
        for ext in RALIX_VALID_EXTENSIONS {
            let directory_index_file_module_name = DIRECTORY_INDEX_MODULE_NAME.to_string() + ext;
            if fs::exists(path.join(&directory_index_file_module_name))? {
                found = true;
                path.push(directory_index_file_module_name);
                break;
            }
        }
    } else {
        for ext in RALIX_VALID_EXTENSIONS {
            let file_module_name = path.to_string_lossy().to_string() + ext;
            if fs::exists(&file_module_name)? {
                path = PathBuf::from(file_module_name);
                found = true;
                break;
            }
        }
    }

    if found {
        let canonicalized = path.canonicalize()?;
        let mut module_name: Identifier =
            canonicalized.file_stem().unwrap().to_string_lossy().into();
        let mut module_path = canonicalized.clone();
        while module_name == DIRECTORY_INDEX_MODULE_NAME.into() {
            module_path = module_path.parent().unwrap().to_path_buf();
            module_name = module_path.file_stem().unwrap().to_string_lossy().into();
        }

        Ok((module_name, canonicalized))
    } else {
        Err(io::Error::new(
            io::ErrorKind::InvalidFilename,
            format!(
                "{} is an invalid path. Valid module extensions are {}",
                path.canonicalize()?.to_string_lossy(),
                RALIX_VALID_EXTENSIONS.join(", ")
            ),
        ))
    }
}