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> {
30 lexer: Lexer<'src>,
31 lookahead: Token<'src>,
32 span: Span,
33}
34
35impl<'src, 'sym> Parser<'src> {
36 pub fn new(source: &'src Source) -> Self {
37 let mut lexer = Lexer::new(source);
38 let lookahead = lexer.next();
39 let span = lexer.span();
40 Self {
41 lexer,
42 lookahead,
43 span,
44 }
45 }
46
47 pub fn parse(&mut self) -> Result<Option<Expr<'src, 'sym>>, ParseError> {
48 if self.lookahead == Token::EOF {
49 return Ok(None);
50 }
51 let expr = self.expression()?;
52 self.expect(&Token::EOF)?;
53 Ok(Some(expr))
54 }
55
56 fn expression(&mut self) -> ParseResult<'src, 'sym> {
57 let lhs = self.primary()?;
58 self.climb(lhs, 1)
59 }
60
61 fn primary(&mut self) -> ParseResult<'src, 'sym> {
62 let span = self.span;
63 match self.lookahead {
64 Token::Number(n) => {
65 self.advance();
66 Ok(Expr::literal(n, span))
67 }
68 Token::Ident(id) => {
69 self.advance();
70 if self.lookahead == Token::ParenOpen {
71 return self.call(id, span);
72 }
73 Ok(Expr::ident(id, span))
74 }
75 Token::Minus => {
76 self.advance();
77 let expr = self.primary()?;
78 let expr = self.climb(expr, Token::Negate.precedence())?;
79 let span = self.span.merge(expr.span);
80 Ok(Expr::unary(UnOp::Neg, expr, span))
81 }
82 Token::ParenOpen => {
83 self.advance();
84 let expr = self.expression()?;
85 self.expect(&Token::ParenClose)?;
86 Ok(expr)
87 }
88 _ => Err(ParseError::UnexpectedToken {
89 found: self.lookahead.lexeme().to_string(),
90 expected: "an expression".to_string(),
91 span,
92 }),
93 }
94 }
95
96 fn call(&mut self, id: &'src str, span: Span) -> ParseResult<'src, 'sym> {
97 self.advance();
99
100 let mut args: Vec<Expr<'src, 'sym>> = Vec::new();
101 while self.lookahead != Token::ParenClose {
102 let arg = self.expression()?;
103 args.push(arg);
104 if self.lookahead == Token::Comma {
105 self.advance();
106 } else {
107 break;
108 }
109 }
110 self.expect(&Token::ParenClose)?;
111
112 let span = span.merge(self.span);
113 Ok(Expr::call(id, args, span))
114 }
115
116 fn climb(&mut self, mut lhs: Expr<'src, 'sym>, min_prec: u8) -> ParseResult<'src, 'sym> {
117 let mut prec = self.lookahead.precedence();
118 while prec >= min_prec {
119 if self.lookahead.is_postfix_unary() {
121 let op = self.lookahead.clone();
122 let op_span = self.span;
123 self.advance();
124 prec = self.lookahead.precedence();
125
126 let unary_op = UnOp::from_token(&op);
127 let span = lhs.span.merge(op_span);
128 lhs = Expr::unary(unary_op, lhs, span);
129 continue;
130 }
131
132 let op = self.lookahead.clone();
133
134 self.advance();
135 let mut rhs = self.primary()?;
136 prec = self.lookahead.precedence();
137
138 while prec > op.precedence()
139 || (self.lookahead.is_right_associative() && prec == op.precedence())
140 {
141 rhs = self.climb(rhs, prec)?;
142 prec = self.lookahead.precedence();
143 }
144
145 let op = BinOp::from_token(&op);
146 let span = lhs.span.merge(rhs.span);
147 lhs = Expr::binary(op, lhs, rhs, span);
148 }
149 Ok(lhs)
150 }
151
152 fn advance(&mut self) {
153 self.lookahead = self.lexer.next();
154 self.span = self.lexer.span();
155 }
156
157 fn accept(&mut self, t: &Token<'src>) -> bool {
158 if self.lookahead == *t {
159 self.advance();
160 true
161 } else {
162 false
163 }
164 }
165
166 fn expect(&mut self, tkn: &Token<'src>) -> Result<(), ParseError> {
167 if !self.accept(tkn) {
168 return Err(ParseError::UnexpectedToken {
169 found: self.lookahead.lexeme().to_string(),
170 expected: tkn.lexeme().to_string(),
171 span: self.span,
172 });
173 }
174 Ok(())
175 }
176}