ํ•ด๋‹ต

use thiserror::Error;
use std::iter::Peekable;
use std::str::Chars;

/// ์‚ฐ์ˆ  ์—ฐ์‚ฐ์ž์ž…๋‹ˆ๋‹ค.
#[derive(Debug, PartialEq, Clone, Copy)]
enum Op {
    Add,
    Sub,
}

/// ํ‘œํ˜„์‹ ์–ธ์–ด์˜ ํ† ํฐ์ž…๋‹ˆ๋‹ค.
#[derive(Debug, PartialEq)]
enum Token {
    Number(String),
    Identifier(String),
    Operator(Op),
}

/// ํ‘œํ˜„์‹ ์–ธ์–ด์˜ ํ‘œํ˜„์‹์ž…๋‹ˆ๋‹ค.
#[derive(Debug, PartialEq)]
enum Expression {
    /// ๋ณ€์ˆ˜ ์ฐธ์กฐ์ž…๋‹ˆ๋‹ค.
    Var(String),
    /// ๋ฆฌํ„ฐ๋Ÿด ์ˆซ์ž์ž…๋‹ˆ๋‹ค.
    Number(u32),
    /// ์ด์ง„ ์—ฐ์‚ฐ์ž…๋‹ˆ๋‹ค.
    Operation(Box<Expression>, Op, Box<Expression>),
}

fn tokenize(input: &str) -> Tokenizer {
    return Tokenizer(input.chars().peekable());
}

#[derive(Debug, Error)]
enum TokenizerError {
    #[error("์ž…๋ ฅ์— ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฌธ์ž '{0}'์ด(๊ฐ€) ์žˆ์Šต๋‹ˆ๋‹ค.")]
    UnexpectedCharacter(char),
}

struct Tokenizer<'a>(Peekable<Chars<'a>>);

impl<'a> Iterator for Tokenizer<'a> {
    type Item = Result<Token, TokenizerError>;

    fn next(&mut self) -> Option<Result<Token, TokenizerError>> {
        let c = self.0.next()?;
        match c {
            '0'..='9' => {
                let mut num = String::from(c);
                while let Some(c @ '0'..='9') = self.0.peek() {
                    num.push(*c);
                    self.0.next();
                }
                Some(Ok(Token::Number(num)))
            }
            'a'..='z' => {
                let mut ident = String::from(c);
                while let Some(c @ ('a'..='z' | '_' | '0'..='9')) = self.0.peek() {
                    ident.push(*c);
                    self.0.next();
                }
                Some(Ok(Token::Identifier(ident)))
            }
            '+' => Some(Ok(Token::Operator(Op::Add))),
            '-' => Some(Ok(Token::Operator(Op::Sub))),
            _ => Some(Err(TokenizerError::UnexpectedCharacter(c))),
        }
    }
}

#[derive(Debug, Error)]
enum ParserError {
    #[error("ํ† ํฐ๋‚˜์ด์ € ์˜ค๋ฅ˜: {0}")]
    TokenizerError(#[from] TokenizerError),
    #[error("์˜ˆ๊ธฐ์น˜ ์•Š์€ ์ž…๋ ฅ ์ข…๋ฃŒ")]
    UnexpectedEOF,
    #[error("์˜ˆ๊ธฐ์น˜ ์•Š์€ ํ† ํฐ {0:?}")]
    UnexpectedToken(Token),
    #[error("์ž˜๋ชป๋œ ๋ฒˆํ˜ธ")]
    InvalidNumber(#[from] std::num::ParseIntError),
}

fn parse(input: &str) -> Result<Expression, ParserError> {
    let mut tokens = tokenize(input);

    fn parse_expr<'a>(
        tokens: &mut Tokenizer<'a>,
    ) -> Result<Expression, ParserError> {
        let tok = tokens.next().ok_or(ParserError::UnexpectedEOF)??;
        let expr = match tok {
            Token::Number(num) => {
                let v = num.parse()?;
                Expression::Number(v)
            }
            Token::Identifier(ident) => Expression::Var(ident),
            Token::Operator(_) => return Err(ParserError::UnexpectedToken(tok)),
        };
        // ์ด์ง„ ์—ฐ์‚ฐ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ด๋ฅผ ํŒŒ์‹ฑํ•ฉ๋‹ˆ๋‹ค.
        Ok(match tokens.next() {
            None => expr,
            Some(Ok(Token::Operator(op))) => Expression::Operation(
                Box::new(expr),
                op,
                Box::new(parse_expr(tokens)?),
            ),
            Some(Err(e)) => return Err(e.into()),
            Some(Ok(tok)) => return Err(ParserError::UnexpectedToken(tok)),
        })
    }

    parse_expr(&mut tokens)
}

fn main() -> anyhow::Result<()> {
    let expr = parse("10+foo+20-30")?;
    println!("{expr:?}");
    Ok(())
}