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

pub(super) fn parse<'a>(lexer: &mut Lexer<'a, Token<'a>>) -> Result<Step<'a>> {
    let action = match lexer.next() {
        Some(token) => match token {
            Ok(Token::Name(name)) => name,
            Ok(_) => return Err(("Unexpected Token", lexer.span())),
            Err(_) => return Err(("Invalid Token", lexer.span())),
        },
        None => return Err(("Erroneous LParen", lexer.span())),
    };
    let objects = {
        let mut objects = Vec::new();
        let mut r_paren = false;

        while let Some(token) = lexer.next() {
            match token {
                Ok(Token::Name(name)) => objects.push(name),
                Ok(Token::RParen) => {
                    r_paren = true;
                    break;
                }
                Ok(_) => return Err(("Unexpected Token", lexer.span())),
                Err(_) => return Err(("Invalid Token", lexer.span())),
            }
        }

        if !r_paren {
            return Err(("Missing RParen", lexer.span()));
        }

        objects
    };
    Ok(Step { action, objects })
}

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

    #[rstest]
    #[case(Ok(crate::plan::Step { action: "a", objects: vec![] }), "a)")]
    #[case(Ok(crate::plan::Step { action: "a", objects: vec!["b"] }), "a b)")]
    #[case(Ok(crate::plan::Step { action: "a", objects: vec!["b", "c"] }), "a b c)")]
    #[case(Err(("Missing RParen", 1..1)), "a")]
    #[case(Err(("Unexpected Token", 0..1)), ")")]
    fn parse(#[case] expected: Result<Step>, #[case] input: &str) {
        let mut lexer = Token::lexer(input);
        assert_eq!(expected, super::parse(&mut lexer));
    }
}