crypt-configs 0.1.0

A simple config format
Documentation
//! Crypt Config Parser
//! Created 6/2/2026 - Nyx

use std::path::Path;

use crate::{body::CryptConfig, lexer::{create_registry, lex_file}, parse::{ParseError, Parser, parse_expression}, resolve::resolve};

// MODULES
mod lexer;
mod parse;
pub mod body;
mod resolve;


/// Opens a crypt config file and builds it into a crypt config object.
/// 
/// See [CryptConfig] for more information on how to handle the data parsed.
/// 
/// # Example
/// 
/// ```
/// use crypt_configs::open_config;
/// 
/// let _config = open_config("tests/test.crypt").expect("Failed to open config!");
/// ```
pub fn open_config<P>(path: P) -> Result<CryptConfig, ParseError> 
where 
    P: AsRef<Path>
{
    let reg = create_registry();

    let tokens = lex_file(path, &reg)?;

    let parser = &mut Parser::new(tokens);
    let ast = parse_expression(parser, 0)?;

    let mut config = CryptConfig::new();
    resolve(&mut config, *ast);
    Ok(config)
}


#[cfg(test)]
mod config_tests {
    use crate::open_config;


    #[test]
    fn basic_file_test() {
        let config = open_config("tests/test.crypt").expect("failed to open config file");

        let version = config.get("version")
            .expect("no version provided!")
            .expect_string("expected version to be a string literal");
        assert_eq!(version, "0.1.0");

        let version = config.get("name")
            .expect("no name provided!")
            .expect_string("expected name to be a string literal");
        assert_eq!(version, "Test");

        let version = config.get("type")
            .expect("no type provided!")
            .expect_string("expected type to be a string literal");
        assert_eq!(version, "Executable");
    }

    #[test]
    fn complex_file_test() {
        let config = open_config("tests/nesting.crypt").expect("failed to open config file");

        let root = config.get("root")
            .expect("no root object found!")
            .expect_nested_config("root isn't a config");

        let inner_1 = root.get("inner_1")
            .expect("no object named inner_1!")
            .expect_nested_config("inner_1 isn't a config");

        let inner_2 = root.get("inner_2")
            .expect("no object named inner_2!")
            .expect_nested_config("inner_2 isn't a config");

        let inner_1_contents = inner_1.get("content")
            .expect("inner_1 doesn't have any content")
            .expect_string("inner_1 content isn't a string");

        let inner_2_contents = inner_2.get("content")
            .expect("inner_2 doesn't have any content")
            .expect_string("inner_2 content isn't a string");
                
        assert_eq!(inner_1_contents, "Contents of inner 1");
        assert_eq!(inner_2_contents, "Contents of inner 2");
    }

}