cup 1.0.0

A config file lib. You can use it, maybe?
Documentation
use crate::Config;
use crate::lexer::Symbol;

macro_rules! expect {
    ($value:expr, $expected:pat) => {
        match $value {
            $expected => {},
            symbol => return Err(ParserError::UnexpectedSymbol(symbol.clone())),
        }
    };
    ($value:expr, $expected:pat, $then:block) => {
        match $value {
            $expected => $then,
            symbol => return Err(ParserError::UnexpectedSymbol(symbol.clone())),
        }
    }
}

#[derive(Debug)]
pub enum ParserError {
    UnexpectedSymbol(Symbol),
    ExpectedSymbol,
    ExpectedSymbolAfter(Symbol),
}

impl std::fmt::Display for ParserError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{self:?}")
    }
}

impl std::error::Error for ParserError {
    fn description(&self) -> &str {
        use ParserError::*;
        match self {
            UnexpectedSymbol(_) => "Unexpected symbol",
            ExpectedSymbol => "Expected symbol",
            ExpectedSymbolAfter(_) => "Expected symbol after",
        }
    }
}

#[derive(Debug, Clone)]
pub enum Type {
    Integer(i64),
    Float(f64),
    String(String),
    Boolean(bool),
    Array(Vec<Type>),
    Dict(Config),
    Null,
}

#[derive(Debug, Clone)]
pub struct Expression {
    pub key: String,
    pub value: Type,
}

impl Expression {
    pub fn new(key: impl AsRef<str>, value: Type) -> Self {
        Self {
            key: key.as_ref().to_string(),
            value,
        }
    }
}

impl PartialEq for Expression {
    fn eq(&self, other: &Self) -> bool {
        self.key == other.key
    }
}

impl Eq for Expression {}

impl std::hash::Hash for Expression {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.key.hash(state);
    }
}

#[derive(Debug, Default)]
pub struct Parser {
    symbols: Vec<Symbol>,
    cursor: isize,
    expressions: Config,
}

impl Parser {
    pub fn new(symbols: Vec<Symbol>) -> Self {
        Self {
            symbols,
            cursor: -1,
            ..Default::default()
        }
    }

    pub fn parse(&mut self) -> Result<Config, ParserError> {
        while self.peek().is_some() {
            let expression = self.expression()?;
            self.expressions.set(expression);
        }

        Ok(self.expressions.clone())
    }

    fn next(&mut self) -> Option<Symbol> {
        self.consume();
        self.symbols.get(self.cursor as usize).cloned()
    }

    fn peek(&self) -> Option<Symbol> {
        self.symbols.get((self.cursor + 1) as usize).cloned()
    }

    fn consume(&mut self) {
        self.cursor += 1;
    }

    fn expression(&mut self) -> Result<Expression, ParserError> {
        let symbol = self.next().unwrap();
        expect!(symbol, Symbol::Identifier(ref key), {
            let symbol = self.next().ok_or(ParserError::ExpectedSymbolAfter(symbol.clone()))?;
            expect!(symbol, Symbol::Assignment);

            self.peek().ok_or(ParserError::ExpectedSymbolAfter(symbol.clone()))?;

            Ok(Expression::new(key, self.value()?))
        })
    }

    fn value(&mut self) -> Result<Type, ParserError> {
        use Symbol::*;
        let symbol = self.peek().ok_or(ParserError::ExpectedSymbol)?;

        let value = match symbol {
            Integer(number) => Type::Integer(number),
            Float(number) => Type::Float(number),
            String(string) => Type::String(string),
            Boolean(state) => Type::Boolean(state),
            Single('[') => Type::Array(self.array()?),
            Single('{') => Type::Dict(self.dict()?),
            Null => Type::Null,
            _ => return Err(ParserError::UnexpectedSymbol(symbol.clone())),
        };

        if !matches!(value, Type::Array(_) | Type::Dict(_)) {
            self.consume();
        }

        Ok(value)
    }

    fn array(&mut self) -> Result<Vec<Type>, ParserError> {
        let mut array: Vec<Type> = Vec::new();

        let symbol = self.next().ok_or(ParserError::ExpectedSymbol)?;
        expect!(symbol, Symbol::Single('['));

        loop {
            let symbol = self.peek().ok_or(ParserError::ExpectedSymbolAfter(self.symbols[self.cursor as usize].clone()))?;
            if let Symbol::Single(']') = symbol {
                self.consume();
                break;
            }

            if !array.is_empty() {
                expect!(symbol, Symbol::Single(','));
                self.consume();
            }

            array.push(self.value()?);
        }

        Ok(array)
    }

    fn dict(&mut self) -> Result<Config, ParserError> {
        let mut dict = Config::default();

        let symbol = self.next().ok_or(ParserError::ExpectedSymbol)?;
        expect!(symbol, Symbol::Single('{'));

        loop {
            let symbol = self.peek().ok_or(ParserError::ExpectedSymbol)?;
            if let Symbol::Single('}') = symbol {
                self.consume();
                break;
            }

            dict.set(self.expression()?);
        }

        Ok(dict)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::lexer::Lexer;

    #[test]
    fn parser_parse() -> Result<(), Box<dyn std::error::Error>> {
        let buffer = br#"
# where is our windows? :O
windows_root = "C:\\"

# is it updated? :D
updated = true

# what is it version? :v
version = 99999"#;

        let mut lexer = Lexer::new(buffer.to_vec(), Default::default());
        let symbols = lexer.lex()?;
        let mut parser = Parser::new(symbols);
        let expressions = parser.parse()?;

        assert_eq!(expressions.0.len(), 3);
        assert!(matches!(expressions.get("windows_root"), Some(Type::String(ref string)) if string == "C:\\"));
        assert!(matches!(expressions.get("updated"), Some(Type::Boolean(true))));
        assert!(matches!(expressions.get("version"), Some(Type::Integer(99999))));

        Ok(())
    }

    #[test]
    fn parser_parse_array() -> Result<(), Box<dyn std::error::Error>> {
        let buffer = b"boolean_byte = [false, true, false, false, false, false, false, true]";
        let mut lexer = Lexer::new(buffer.to_vec(), Default::default());
        let symbols = lexer.lex()?;
        let mut parser = Parser::new(symbols);
        let expressions = parser.parse()?;

        assert_eq!(expressions.0.len(), 1);
        assert!(matches!(expressions.get("boolean_byte"), Some(Type::Array(ref array)) if array.len() == 8));

        Ok(())
    }

    #[test]
    fn parser_parse_2d_array() -> Result<(), Box<dyn std::error::Error>> {
        let buffer = b"matrix = [[1, 0], [0, 1]]";
        let mut lexer = Lexer::new(buffer.to_vec(), Default::default());
        let symbols = lexer.lex()?;
        let mut parser = Parser::new(symbols);
        let expressions = parser.parse()?;

        assert_eq!(expressions.0.len(), 1);
        assert!(matches!(expressions.get("matrix"), Some(Type::Array(ref array)) if array.len() == 2));

        assert!(matches!(expressions.get("matrix"), Some(Type::Array(ref array))
            if matches!(array[0], Type::Array(ref array)
                if array.len() == 2)));

        assert!(matches!(expressions.get("matrix"), Some(Type::Array(ref array))
            if matches!(array[1], Type::Array(ref array)
                if array.len() == 2)));

        Ok(())
    }

    #[test]
    fn parser_parse_dict() -> Result<(), Box<dyn std::error::Error>> {
        let buffer = b"jsobject = {\n  prototype = null\n  banana = \"'b' + 'a' + + 'a' + 'a'\"\n  enemy_confused = true\n}";
        let mut lexer = Lexer::new(buffer.to_vec(), Default::default());
        let symbols = lexer.lex()?;
        let mut parser = Parser::new(symbols);
        let expressions = parser.parse()?;

        assert_eq!(expressions.0.len(), 1);

        if let Type::Dict(dict) = expressions.get("jsobject").unwrap() {
            assert_eq!(dict.0.len(), 2);
            
            assert!(dict.get("prototype").is_none());
            assert!(matches!(dict.get("banana"), Some(Type::String(ref string)) if string == "'b' + 'a' + + 'a' + 'a'"));
            assert!(matches!(dict.get("enemy_confused"), Some(Type::Boolean(true))));
        } else {
            panic!("panik");
        };

        Ok(())
    }

    #[test]
    fn parser_parse_nested_dict() -> Result<(), Box<dyn std::error::Error>> {
        let buffer = br#"
audio_output = {
  type = "shout"
  name = "my cool stream"
  host = "localhost"
  port = 80
  mount = "/var/lib/mpd/http.ogg"
  password = "p4ssw0rd"
  quality = 5.0
  bitrate = 128
  format = {
    samples = 48_000
    bits = 16
    channels = 2
  }
  encoding = "mp3"
}"#;

        let mut lexer = Lexer::new(buffer.to_vec(), Default::default());
        let symbols = lexer.lex()?;
        let mut parser = Parser::new(symbols);
        let expressions = parser.parse()?;

        assert_eq!(expressions.0.len(), 1);

        if let Type::Dict(dict) = expressions.get("audio_output").unwrap() {
            assert_eq!(dict.0.len(), 10);

            if let Type::Dict(dict) = dict.get("format").unwrap() {
                assert_eq!(dict.0.len(), 3);
            }
        }

        Ok(())
    }
}