expr_solver/
parser.rs

1//! Recursive descent parser for mathematical expressions.
2
3use super::ast::{BinOp, Expr, UnOp};
4use super::error::ParseError;
5use super::lexer::Lexer;
6use crate::span::Span;
7use crate::token::Token;
8
9pub type ParseResult = Result<Expr, ParseError>;
10
11/// Recursive descent parser for mathematical expressions.
12///
13/// Uses operator precedence climbing for efficient binary operator parsing.
14///
15/// # Examples
16///
17/// ```
18/// use expr_solver::Parser;
19///
20/// let mut parser = Parser::new("2 + 3 * 4");
21/// let ast = parser.parse().unwrap();
22/// assert!(ast.is_some());
23/// ```
24pub struct Parser<'src> {
25    input: &'src str,
26}
27
28impl<'src> Parser<'src> {
29    /// Creates a new parser from a string slice.
30    pub fn new(input: &'src str) -> Self {
31        Self { input }
32    }
33
34    /// Parses the input into an abstract syntax tree.
35    ///
36    /// Returns `None` for empty input, or an expression on success.
37    pub fn parse(&mut self) -> Result<Option<Expr>, ParseError> {
38        let mut lexer = Lexer::new(self.input);
39        let mut lookahead = lexer.next();
40        let mut span = lexer.span();
41
42        if lookahead == Token::Eof {
43            return Ok(None);
44        }
45
46        let expr = Self::expression(&mut lexer, &mut lookahead, &mut span)?;
47        Self::expect_token(&mut lexer, &mut lookahead, &mut span, &Token::Eof)?;
48        Ok(Some(expr))
49    }
50
51    fn expression<'lex>(
52        lexer: &mut Lexer<'lex>,
53        lookahead: &mut Token<'lex>,
54        span: &mut Span,
55    ) -> ParseResult {
56        let lhs = Self::primary(lexer, lookahead, span)?;
57        Self::climb(lexer, lookahead, span, lhs, 1)
58    }
59
60    fn primary<'lex>(
61        lexer: &mut Lexer<'lex>,
62        lookahead: &mut Token<'lex>,
63        span: &mut Span,
64    ) -> ParseResult {
65        let current_span = *span;
66        match *lookahead {
67            Token::Number(n) => {
68                Self::advance(lexer, lookahead, span);
69                Ok(Expr::literal(n, current_span))
70            }
71            Token::Ident(id) => {
72                let id_string = id.to_string();
73                Self::advance(lexer, lookahead, span);
74                if *lookahead == Token::ParenOpen {
75                    return Self::call(lexer, lookahead, span, id_string, current_span);
76                }
77                Ok(Expr::ident(id_string, current_span))
78            }
79            Token::Minus => {
80                Self::advance(lexer, lookahead, span);
81                let expr = Self::primary(lexer, lookahead, span)?;
82                let expr = Self::climb(lexer, lookahead, span, expr, Token::Negate.precedence())?;
83                let full_span = current_span.merge(expr.span);
84                Ok(Expr::unary(UnOp::Neg, expr, full_span))
85            }
86            Token::ParenOpen => {
87                Self::advance(lexer, lookahead, span);
88                let expr = Self::expression(lexer, lookahead, span)?;
89                Self::expect_token(lexer, lookahead, span, &Token::ParenClose)?;
90                Ok(expr)
91            }
92            _ => Err(ParseError::UnexpectedToken {
93                message: format!(
94                    "unexpected token '{}', expected an expression",
95                    lookahead.lexeme()
96                ),
97                span: current_span,
98            }),
99        }
100    }
101
102    fn call<'lex>(
103        lexer: &mut Lexer<'lex>,
104        lookahead: &mut Token<'lex>,
105        span: &mut Span,
106        id: String,
107        start_span: Span,
108    ) -> ParseResult {
109        // assume lookahead is '('
110        Self::advance(lexer, lookahead, span);
111
112        let mut args: Vec<Expr> = Vec::new();
113        while *lookahead != Token::ParenClose {
114            let arg = Self::expression(lexer, lookahead, span)?;
115            args.push(arg);
116            if *lookahead == Token::Comma {
117                Self::advance(lexer, lookahead, span);
118            } else {
119                break;
120            }
121        }
122        Self::expect_token(lexer, lookahead, span, &Token::ParenClose)?;
123
124        let full_span = start_span.merge(*span);
125        Ok(Expr::call(id, args, full_span))
126    }
127
128    fn climb<'lex>(
129        lexer: &mut Lexer<'lex>,
130        lookahead: &mut Token<'lex>,
131        span: &mut Span,
132        mut lhs: Expr,
133        min_prec: u8,
134    ) -> ParseResult {
135        let mut prec = lookahead.precedence();
136        while prec >= min_prec {
137            // Handle postfix unary operators
138            if lookahead.is_postfix_unary() {
139                let op = lookahead.clone();
140                let op_span = *span;
141                Self::advance(lexer, lookahead, span);
142                prec = lookahead.precedence();
143
144                let unary_op = UnOp::from_token(&op);
145                let full_span = lhs.span.merge(op_span);
146                lhs = Expr::unary(unary_op, lhs, full_span);
147                continue;
148            }
149
150            let op = lookahead.clone();
151
152            Self::advance(lexer, lookahead, span);
153            let mut rhs = Self::primary(lexer, lookahead, span)?;
154            prec = lookahead.precedence();
155
156            while prec > op.precedence()
157                || (lookahead.is_right_associative() && prec == op.precedence())
158            {
159                rhs = Self::climb(lexer, lookahead, span, rhs, prec)?;
160                prec = lookahead.precedence();
161            }
162
163            let binop = BinOp::from_token(&op);
164            let full_span = lhs.span.merge(rhs.span);
165            lhs = Expr::binary(binop, lhs, rhs, full_span);
166        }
167        Ok(lhs)
168    }
169
170    fn advance<'lex>(lexer: &mut Lexer<'lex>, lookahead: &mut Token<'lex>, span: &mut Span) {
171        *lookahead = lexer.next();
172        *span = lexer.span();
173    }
174
175    fn expect_token<'lex>(
176        lexer: &mut Lexer<'lex>,
177        lookahead: &mut Token<'lex>,
178        span: &mut Span,
179        expected: &Token<'lex>,
180    ) -> Result<(), ParseError> {
181        if lookahead == expected {
182            Self::advance(lexer, lookahead, span);
183            Ok(())
184        } else {
185            Err(ParseError::UnexpectedToken {
186                message: format!(
187                    "unexpected token '{}', expected '{}'",
188                    lookahead.lexeme(),
189                    expected.lexeme()
190                ),
191                span: *span,
192            })
193        }
194    }
195}