Documentation
use super::parser::{Parser, ParserError, ParserResult};
use super::token::Token;

pub mod select;
pub mod create;
pub mod columns;

pub trait Syntax: Sized {
    type Output;
    fn parse(parser: &mut Parser) -> ParserResult<Self::Output>;
}

struct CommaDelimited<R: Syntax>(R);
impl<R> SyntaxExt for R
where
    R: Syntax,
{
}

pub trait SyntaxExt: Syntax {
    fn parse_comma_delimited(parser: &mut Parser) -> ParserResult<Vec<Self::Output>> {
        CommaDelimited::<Self>::parse(parser)
    }
}

impl<R: Syntax> Syntax for CommaDelimited<R> {
    type Output = Vec<R::Output>;

    fn parse(parser: &mut Parser) -> ParserResult<Self::Output> {
        let mut v: Vec<R::Output> = Vec::new();
        v.push(R::parse(parser).unwrap());
        while parser.pop_if(&Token::COMMA) {
            let value = R::parse(parser).unwrap();
            v.push(value);
        }
        Ok(v)
    }
}

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

    #[test]
    fn comma_delimited() {
        let mut parser = Lexer::lex("select row_1, row_2, row_3 from my_table where row_id > 0;")
            .unwrap();

        parser.pop().unwrap();
        let v = columns::Column::parse_comma_delimited(&mut parser).unwrap();
        let correct = vec![
            Token::Identifier("row_1".into()),
            Token::Identifier("row_2".into()),
            Token::Identifier("row_3".into()),
        ];

        assert_eq!(correct.len(), v.len());
        for (tok, _v) in correct.into_iter().zip(v.into_iter()) {
            match _v {
                columns::Column::Expr(t) => assert_eq!(t, tok),
                _ => panic!("Mismatch!"),
            };
        }
    }
}