Documentation
use super::{token::Token, Result, Type};
use logos::Lexer;

pub fn parse<'a>(lexer: &mut Lexer<'a, Token<'a>>) -> Result<Vec<Type<'a>>> {
    let mut types = Vec::new();

    let mut queue: Vec<&'a str> = Vec::new();
    while let Some(token) = lexer.next() {
        match token {
            Ok(Token::Name(name)) => queue.push(name),
            Ok(Token::TypeSeparator) => match lexer.next() {
                Some(token) => match token {
                    Ok(Token::Name(name)) => {
                        for item in queue.iter() {
                            types.push(Type {
                                name: item,
                                parent: Some(name),
                            });
                        }
                        queue.clear();
                    }
                    Ok(_) => return Err(("unexpected token", lexer.span())),
                    Err(_) => return Err(("invalid token", lexer.span())),
                },
                None => return Err(("erroneous type separator", lexer.span())),
            },
            Ok(Token::RParen) => break,
            Ok(_) => return Err(("unexpected token", lexer.span())),
            Err(_) => return Err(("invalid token", lexer.span())),
        }
    }

    for item in queue.iter() {
        types.push(Type {
            name: item,
            parent: None,
        });
    }

    Ok(types)
}

#[cfg(test)]
mod test {
    use super::{Result, Token, Type};
    use logos::Logos;
    use rstest::rstest;

    #[rstest]
    #[case(Ok(vec![Type { name: "a", parent: None }]), "a)")]
    #[case(Ok(vec![Type { name: "a", parent: Some("b") }]), "a - b)")]
    #[case(Ok(vec![
        Type { name: "a", parent: Some("c") },
        Type { name: "b", parent: Some("c") }
    ]), "a b - c)")]
    #[case(Ok(vec![
        Type { name: "b", parent: Some("c") },
        Type { name: "a", parent: Some("b") }
    ]), "b - c a - b)")]
    #[case(Ok(vec![
        Type { name: "b", parent: Some("c") },
        Type { name: "a", parent: None }
    ]), "b - c a)")]
    fn parse(#[case] expected: Result<Vec<Type>>, #[case] input: &str) {
        let mut lexer = Token::lexer(input);
        assert_eq!(expected, super::parse(&mut lexer));
    }
}