utterance 0.1.3

A parser library for creating readable, natural-language-inspired domain-specific languages.
Documentation
use crate::lexer::{Lexer, Number, Symbol, Token, TokenKind, TokenType};
use crate::parser::expectation::{ExpectationError, Match, NumberKind, Statement, StatementKind};

fn peek_token_or_error<'input, const P: usize>(
    lexer: &mut Lexer<'input, P>,
    n: usize,
) -> Result<Token<'input>, ExpectationError> {
    match lexer.peek_token(n) {
        Some(Ok(token)) => Ok(token.clone()),
        Some(Err(err)) => Err(ExpectationError::Lex(err.clone())),
        None => Err(ExpectationError::EndOfInput),
    }
}

fn expect_kinds(token: &Token, expected: &[TokenKind]) -> bool {
    expected.contains(&token.token_type().kind())
}

pub(crate) fn expect_capitalize_word<'a, const P: usize>(
    lexer: &mut Lexer<P>,
) -> Result<Match<'a>, ExpectationError> {
    let token = peek_token_or_error(lexer, 0)?;

    if let TokenType::Word(w) = token.token_type()
        && w.chars().next().unwrap().is_uppercase()
    {
        Ok(Match::new(0, Statement::CapitalizeWord))
    } else {
        Err(ExpectationError::ExpectedStatements {
            expected: StatementKind::CapitalizeWord,
            text: token.to_string(),
        })
    }
}

pub(crate) fn expect_word<'input, const P: usize>(
    lexer: &mut Lexer<'input, P>,
) -> Result<Match<'input>, ExpectationError> {
    let token = peek_token_or_error(lexer, 0)?;

    match token.token_type() {
        TokenType::Word(w) => Ok(Match::new(1, Statement::Word(w))),
        _ => Err(ExpectationError::ExpectedStatements {
            expected: StatementKind::Word,
            text: token.to_string(),
        }),
    }
}

pub(crate) fn expect_exact_word<'input, const P: usize>(
    lexer: &mut Lexer<'input, P>,
    expected: &'static str,
) -> Result<Match<'input>, ExpectationError> {
    let token = peek_token_or_error(lexer, 0)?;

    if let TokenType::Word(w) = token.token_type()
        && w == &expected
    {
        Ok(Match::new(1, Statement::Word(w)))
    } else {
        Err(ExpectationError::ExpectedStatements {
            expected: StatementKind::ExactWord(expected),
            text: token.to_string(),
        })
    }
}

pub(crate) fn expect_one_of_words<'input, const P: usize>(
    lexer: &mut Lexer<'input, P>,
    expected: &'static [&'static str],
) -> Result<Match<'input>, ExpectationError> {
    let token = peek_token_or_error(lexer, 0)?;

    if let TokenType::Word(w) = token.token_type()
        && expected.iter().any(|e| e == w)
    {
        return Ok(Match::new(1, Statement::ExactWord(w)));
    }

    Err(ExpectationError::ExpectedStatements {
        expected: StatementKind::OneOfExactWords(expected),
        text: token.to_string(),
    })
}

pub(crate) fn expect_comment<'a, const P: usize>(
    lexer: &mut Lexer<P>,
) -> Result<Match<'a>, ExpectationError> {
    let token = peek_token_or_error(lexer, 0)?;

    if StatementKind::from(token.token_type()) != *lexer.comment_symbol() {
        return Err(ExpectationError::ExpectedStatements {
            expected: StatementKind::Comment,
            text: token.to_string(),
        });
    }

    let (n, _) = lexer.peek_until_kind(&[TokenKind::Newline, TokenKind::End])?;

    Ok(Match::new(n, Statement::Comment))
}

pub(crate) fn expect_number<'a, const P: usize>(
    lexer: &mut Lexer<P>,
    expected: NumberKind,
) -> Result<Match<'a>, ExpectationError> {
    let token = peek_token_or_error(lexer, 0)?;

    match token.token_type() {
        TokenType::Number(number) => {
            let mut number = *number;

            if !number.try_convert_into(expected) {
                return Err(ExpectationError::ExpectedStatements {
                    expected: StatementKind::Number(expected),
                    text: token.to_string(),
                });
            }

            Ok(Match::new(1, Statement::Number(number)))
        }

        _ => Err(ExpectationError::ExpectedStatements {
            expected: StatementKind::Number(expected),
            text: token.to_string(),
        }),
    }
}

pub(crate) fn expect_exact_number<'a, const P: usize>(
    lexer: &mut Lexer<P>,
    expected: Number,
) -> Result<Match<'a>, ExpectationError> {
    let token = peek_token_or_error(lexer, 0)?;

    match token.token_type() {
        TokenType::Number(number) => {
            let mut number = *number;

            if !number.try_convert_into(expected.into()) {
                return Err(ExpectationError::ExpectedStatements {
                    expected: StatementKind::Number(expected.into()),
                    text: token.to_string(),
                });
            }

            if number == expected {
                Ok(Match::new(1, Statement::Number(expected)))
            } else {
                Err(ExpectationError::ExpectedStatements {
                    expected: StatementKind::Number(expected.into()),
                    text: token.to_string(),
                })
            }
        }

        _ => Err(ExpectationError::ExpectedStatements {
            expected: StatementKind::Number(expected.into()),
            text: token.to_string(),
        }),
    }
}

pub(crate) fn expect_new_line_or_end<'a, const P: usize>(
    lexer: &mut Lexer<P>,
) -> Result<Match<'a>, ExpectationError> {
    let token = peek_token_or_error(lexer, 0)?;

    if !expect_kinds(&token, &[TokenKind::Newline, TokenKind::End]) {
        return Err(ExpectationError::ExpectedStatements {
            expected: StatementKind::NewLineOrEnd,
            text: token.to_string(),
        });
    }

    Ok(Match::new(1, Statement::NewLineOrEnd))
}

pub(crate) fn expect_noop<'a, const P: usize>(
    _: &mut Lexer<P>,
) -> Result<Match<'a>, ExpectationError> {
    Ok(Match::new(0, Statement::Noop))
}

pub(crate) fn expect_symbol<'a, const P: usize>(
    lexer: &mut Lexer<P>,
    expected: Symbol,
) -> Result<Match<'a>, ExpectationError> {
    let token = peek_token_or_error(lexer, 0)?;

    match token.token_type() {
        TokenType::Symbol(symbol) if *symbol == expected => {
            Ok(Match::new(1, Statement::Symbol(expected)))
        }
        _ => Err(ExpectationError::ExpectedStatements {
            expected: StatementKind::Symbol(expected),
            text: token.to_string(),
        }),
    }
}

pub(crate) fn expect_double_symbol<'a, const P: usize>(
    lexer: &mut Lexer<P>,
    expected: Symbol,
) -> Result<Match<'a>, ExpectationError> {
    let token = peek_token_or_error(lexer, 0)?;

    match token.token_type() {
        TokenType::DoubleSymbol(symbol) if *symbol == expected => {
            Ok(Match::new(1, Statement::DoubleSymbol(expected)))
        }
        _ => Err(ExpectationError::ExpectedStatements {
            expected: StatementKind::DoubleSymbol(expected),
            text: token.to_string(),
        }),
    }
}