1use crate::ast::{BinOp, Expr, UnOp};
2use crate::lexer::Lexer;
3use crate::source::Source;
4use crate::span::{Span, SpanError};
5use crate::token::Token;
6use thiserror::Error;
7
8#[derive(Error, Debug, Clone)]
10pub enum ParseError {
11 #[error("Unexpected token '{found}', expected '{expected}'")]
12 UnexpectedToken {
13 found: String,
14 expected: String,
15 span: Span,
16 },
17}
18
19impl SpanError for ParseError {
20 fn span(&self) -> Span {
21 match self {
22 ParseError::UnexpectedToken { span, .. } => *span,
23 }
24 }
25}
26
27pub type ParseResult<'src, 'sym> = Result<Expr<'src, 'sym>, ParseError>;
28
29pub struct Parser<'src> {
33 lexer: Lexer<'src>,
34 lookahead: Token<'src>,
35 span: Span,
36}
37
38impl<'src, 'sym> Parser<'src> {
39 pub fn new(source: &'src Source) -> Self {
41 let mut lexer = Lexer::new(source);
42 let lookahead = lexer.next();
43 let span = lexer.span();
44 Self {
45 lexer,
46 lookahead,
47 span,
48 }
49 }
50
51 pub fn parse(&mut self) -> Result<Option<Expr<'src, 'sym>>, ParseError> {
55 if self.lookahead == Token::EOF {
56 return Ok(None);
57 }
58 let expr = self.expression()?;
59 self.expect(&Token::EOF)?;
60 Ok(Some(expr))
61 }
62
63 fn expression(&mut self) -> ParseResult<'src, 'sym> {
64 let lhs = self.primary()?;
65 self.climb(lhs, 1)
66 }
67
68 fn primary(&mut self) -> ParseResult<'src, 'sym> {
69 let span = self.span;
70 match self.lookahead {
71 Token::Number(n) => {
72 self.advance();
73 Ok(Expr::literal(n, span))
74 }
75 Token::Ident(id) => {
76 self.advance();
77 if self.lookahead == Token::ParenOpen {
78 return self.call(id, span);
79 }
80 Ok(Expr::ident(id, span))
81 }
82 Token::Minus => {
83 self.advance();
84 let expr = self.primary()?;
85 let expr = self.climb(expr, Token::Negate.precedence())?;
86 let span = self.span.merge(expr.span);
87 Ok(Expr::unary(UnOp::Neg, expr, span))
88 }
89 Token::ParenOpen => {
90 self.advance();
91 let expr = self.expression()?;
92 self.expect(&Token::ParenClose)?;
93 Ok(expr)
94 }
95 _ => Err(ParseError::UnexpectedToken {
96 found: self.lookahead.lexeme().to_string(),
97 expected: "an expression".to_string(),
98 span,
99 }),
100 }
101 }
102
103 fn call(&mut self, id: &'src str, span: Span) -> ParseResult<'src, 'sym> {
104 self.advance();
106
107 let mut args: Vec<Expr<'src, 'sym>> = Vec::new();
108 while self.lookahead != Token::ParenClose {
109 let arg = self.expression()?;
110 args.push(arg);
111 if self.lookahead == Token::Comma {
112 self.advance();
113 } else {
114 break;
115 }
116 }
117 self.expect(&Token::ParenClose)?;
118
119 let span = span.merge(self.span);
120 Ok(Expr::call(id, args, span))
121 }
122
123 fn climb(&mut self, mut lhs: Expr<'src, 'sym>, min_prec: u8) -> ParseResult<'src, 'sym> {
124 let mut prec = self.lookahead.precedence();
125 while prec >= min_prec {
126 if self.lookahead.is_postfix_unary() {
128 let op = self.lookahead.clone();
129 let op_span = self.span;
130 self.advance();
131 prec = self.lookahead.precedence();
132
133 let unary_op = UnOp::from_token(&op);
134 let span = lhs.span.merge(op_span);
135 lhs = Expr::unary(unary_op, lhs, span);
136 continue;
137 }
138
139 let op = self.lookahead.clone();
140
141 self.advance();
142 let mut rhs = self.primary()?;
143 prec = self.lookahead.precedence();
144
145 while prec > op.precedence()
146 || (self.lookahead.is_right_associative() && prec == op.precedence())
147 {
148 rhs = self.climb(rhs, prec)?;
149 prec = self.lookahead.precedence();
150 }
151
152 let op = BinOp::from_token(&op);
153 let span = lhs.span.merge(rhs.span);
154 lhs = Expr::binary(op, lhs, rhs, span);
155 }
156 Ok(lhs)
157 }
158
159 fn advance(&mut self) {
160 self.lookahead = self.lexer.next();
161 self.span = self.lexer.span();
162 }
163
164 fn accept(&mut self, t: &Token<'src>) -> bool {
165 if self.lookahead == *t {
166 self.advance();
167 true
168 } else {
169 false
170 }
171 }
172
173 fn expect(&mut self, tkn: &Token<'src>) -> Result<(), ParseError> {
174 if !self.accept(tkn) {
175 return Err(ParseError::UnexpectedToken {
176 found: self.lookahead.lexeme().to_string(),
177 expected: tkn.lexeme().to_string(),
178 span: self.span,
179 });
180 }
181 Ok(())
182 }
183}