skiff/parser/
parselets.rs

1use crate::ast::{Ast, AstNode, BinOp, SrcLoc};
2use crate::lexer::lex::Token;
3use crate::parser::parse::{self, parse_expr, parse_params};
4use crate::parser::patterns::parse::parse_pattern;
5use crate::parser::util;
6use util::expect_and_consume;
7
8use super::parse::parse_identifier;
9use super::types::parse::parse_type;
10use super::util::{ast_op_to_token_op, consume_if_present};
11
12pub trait PrefixParselet {
13    fn parse(
14        &self,
15        tokens: &mut Vec<(Token, std::ops::Range<usize>)>,
16        current_token: (Token, std::ops::Range<usize>),
17        is_top_level: bool,
18    ) -> Result<Ast, util::ParseError>;
19}
20pub trait InfixParselet {
21    fn parse(
22        &self,
23        tokens: &mut Vec<(Token, std::ops::Range<usize>)>,
24        left_node: Ast,
25        current_token: (Token, std::ops::Range<usize>),
26    ) -> Result<Ast, util::ParseError>;
27}
28
29pub trait PostfixParselet {
30    fn parse(
31        &self,
32        tokens: &mut Vec<(Token, std::ops::Range<usize>)>,
33        left_node: Ast,
34        current_token: (Token, std::ops::Range<usize>),
35    ) -> Result<Ast, util::ParseError>;
36}
37
38pub struct NumberParselet {}
39impl PrefixParselet for NumberParselet {
40    fn parse(
41        &self,
42        _tokens: &mut Vec<(Token, std::ops::Range<usize>)>,
43        current_token: (Token, std::ops::Range<usize>),
44        _is_top_level: bool,
45    ) -> Result<Ast, util::ParseError> {
46        match current_token {
47            (Token::Number(n), span) => Ok(Ast::new(AstNode::NumberNode(n), SrcLoc { span })),
48            _ => panic!("Tried to use number parselet with non-number token"),
49        }
50    }
51}
52
53pub struct BoolParselet {}
54impl PrefixParselet for BoolParselet {
55    fn parse(
56        &self,
57        _tokens: &mut Vec<(Token, std::ops::Range<usize>)>,
58        current_token: (Token, std::ops::Range<usize>),
59        _is_top_level: bool,
60    ) -> Result<Ast, util::ParseError> {
61        match current_token {
62            (Token::Bool(v), span) => Ok(Ast::new(AstNode::BoolNode(v), SrcLoc { span })),
63            _ => panic!("Tried to use bool parselet with non-bool token"),
64        }
65    }
66}
67
68pub struct FunctionParselet {}
69impl PrefixParselet for FunctionParselet {
70    fn parse(
71        &self,
72        tokens: &mut Vec<(Token, std::ops::Range<usize>)>,
73        current_token: (Token, std::ops::Range<usize>),
74        is_top_level: bool,
75    ) -> Result<Ast, util::ParseError> {
76        if !is_top_level {
77            return Err(util::ParseError(
78                "Function definitions are only allowed at the top level".to_string(),
79                Some(current_token.1),
80            ));
81        }
82
83        let span_start = current_token.1.start;
84
85        let func_name = match tokens.pop() {
86            Some((Token::Identifier(name), _)) => Ok(name),
87            Some((_, span)) => Err(util::ParseError(
88                "Found non-identifier in function name".to_string(),
89                Some(span.clone()),
90            )),
91            None => Err(util::ParseError(
92                "Ran out of tokens while parsing function name".to_string(),
93                None,
94            )),
95        }?;
96
97        expect_and_consume(tokens, Token::LParen)?;
98
99        let params = parse::parse_params(tokens)?;
100
101        // See if there's a return type to parse
102        let mut return_type = None;
103        match tokens.last() {
104            Some((Token::ThinArrow, _)) => {
105                tokens.pop();
106                return_type = Some(parse_type(tokens)?);
107            }
108            None => {
109                return Err(util::ParseError(
110                    "Ran out of tokens while parsing function name".to_string(),
111                    None,
112                ))
113            }
114            _ => {}
115        };
116
117        expect_and_consume(tokens, Token::Colon)?;
118
119        let body = parse::parse_expr(tokens, 0, false)?;
120
121        let span_end = expect_and_consume(tokens, Token::End)?.end;
122
123        return Ok(Ast::new(
124            AstNode::FunctionNode(
125                func_name,
126                params,
127                return_type.map_or(None, |v| Some(v.0)),
128                Box::new(body),
129            ),
130            SrcLoc {
131                span: span_start..span_end,
132            },
133        ));
134    }
135}
136
137pub struct LambdaParselet {}
138impl PrefixParselet for LambdaParselet {
139    fn parse(
140        &self,
141        tokens: &mut Vec<(Token, std::ops::Range<usize>)>,
142        current_token: (Token, std::ops::Range<usize>),
143        _is_top_level: bool,
144    ) -> Result<Ast, util::ParseError> {
145        let span_start = current_token.1.start;
146
147        expect_and_consume(tokens, Token::LParen)?;
148
149        let params = parse::parse_params(tokens)?;
150
151        expect_and_consume(tokens, Token::Colon)?;
152
153        let body = parse::parse_expr(tokens, 0, false)?;
154
155        let span_end = expect_and_consume(tokens, Token::End)?.end;
156
157        return Ok(Ast::new(
158            AstNode::LambdaNode(params, Box::new(body)),
159            SrcLoc {
160                span: span_start..span_end,
161            },
162        ));
163    }
164}
165
166pub struct IfParselet {}
167impl PrefixParselet for IfParselet {
168    fn parse(
169        &self,
170        tokens: &mut Vec<(Token, std::ops::Range<usize>)>,
171        current_token: (Token, std::ops::Range<usize>),
172        _is_top_level: bool,
173    ) -> Result<Ast, util::ParseError> {
174        let span_start = current_token.1.start;
175
176        let mut conditions = vec![];
177        let mut bodies = vec![];
178        conditions.push(parse::parse_expr(tokens, 0, false)?);
179        expect_and_consume(tokens, Token::Colon)?;
180        bodies.push(parse::parse_expr(tokens, 0, false)?);
181
182        let altern = loop {
183            match tokens.pop() {
184                Some((Token::Elif, _)) => {
185                    conditions.push(parse::parse_expr(tokens, 0, false)?);
186                    expect_and_consume(tokens, Token::Colon)?;
187                    bodies.push(parse::parse_expr(tokens, 0, false)?);
188                }
189                Some((Token::Else, _)) => {
190                    expect_and_consume(tokens, Token::Colon)?;
191                    break parse::parse_expr(tokens, 0, false)?;
192                }
193                Some((_, span)) => {
194                    return Err(util::ParseError(
195                        "Expected `else` or `elif`".to_string(),
196                        Some(span),
197                    ))
198                }
199                None => {
200                    return Err(util::ParseError(
201                        "Ran out of tokens while parsing conditional".to_string(),
202                        None,
203                    ))
204                }
205            }
206        };
207
208        let span_end = expect_and_consume(tokens, Token::End)?.end;
209
210        return Ok(Ast::new(
211            AstNode::IfNode(
212                conditions
213                    .into_iter()
214                    .zip(bodies.into_iter())
215                    .collect::<Vec<(Ast, Ast)>>(),
216                Box::new(altern),
217            ),
218            SrcLoc {
219                span: span_start..span_end,
220            },
221        ));
222    }
223}
224
225pub struct LetParselet {}
226impl PrefixParselet for LetParselet {
227    fn parse(
228        &self,
229        tokens: &mut Vec<(Token, std::ops::Range<usize>)>,
230        current_token: (Token, std::ops::Range<usize>),
231        is_top_level: bool,
232    ) -> Result<Ast, util::ParseError> {
233        let span_start = current_token.1.start;
234
235        let (id, _) = parse_identifier(None, tokens)?;
236
237        // TODO: make the span_end at the true end of the expression
238        let span_end = expect_and_consume(tokens, Token::Eq)?.end;
239
240        let binding = parse::parse_expr(tokens, 0, false)?;
241        if is_top_level {
242            return Ok(Ast::new(
243                AstNode::LetNodeTopLevel(id, Box::new(binding)),
244                SrcLoc {
245                    span: span_start..span_end,
246                },
247            ));
248        } else {
249            let body = parse::parse_expr(tokens, 0, false)?;
250            return Ok(Ast::new(
251                AstNode::LetNode(id, Box::new(binding), Box::new(body)),
252                SrcLoc {
253                    span: span_start..span_end,
254                },
255            ));
256        }
257    }
258}
259
260pub struct IdentifierParselet {}
261impl PrefixParselet for IdentifierParselet {
262    fn parse(
263        &self,
264        _tokens: &mut Vec<(Token, std::ops::Range<usize>)>,
265        current_token: (Token, std::ops::Range<usize>),
266        _is_top_level: bool,
267    ) -> Result<Ast, util::ParseError> {
268        match current_token {
269            (Token::Identifier(id), span) => Ok(Ast::new(AstNode::VarNode(id), SrcLoc { span })),
270            _ => panic!("Tried to use identifier parselet with non-id token"),
271        }
272    }
273}
274
275pub struct ParenthesisParselet {}
276impl PrefixParselet for ParenthesisParselet {
277    fn parse(
278        &self,
279        tokens: &mut Vec<(Token, std::ops::Range<usize>)>,
280        _current_token: (Token, std::ops::Range<usize>),
281        _is_top_level: bool,
282    ) -> Result<Ast, util::ParseError> {
283        let expr = parse::parse_expr(tokens, 0, false)?;
284
285        expect_and_consume(tokens, Token::RParen)?;
286
287        return Ok(expr);
288    }
289}
290
291pub struct DataParselet {}
292impl PrefixParselet for DataParselet {
293    fn parse(
294        &self,
295        tokens: &mut Vec<(Token, std::ops::Range<usize>)>,
296        current_token: (Token, std::ops::Range<usize>),
297        is_top_level: bool,
298    ) -> Result<Ast, util::ParseError> {
299        if !is_top_level {
300            return Err(util::ParseError(
301                "Data declarations can only exist at the top level".to_string(),
302                Some(current_token.1),
303            ));
304        }
305
306        let (data_name, span_start) = match tokens.pop() {
307            Some((Token::Identifier(id), span)) => Ok((id, span.start)),
308            Some((_, span)) => Err(util::ParseError(
309                "Found non-identifier as data declaration name".to_string(),
310                Some(span),
311            )),
312            None => Err(util::ParseError(
313                "Ran out of tokens while parsing data declaration".to_string(),
314                None,
315            )),
316        }?;
317
318        expect_and_consume(tokens, Token::Colon)?;
319        // Initial pipe character is optional
320        consume_if_present(tokens, Token::Pipe)?;
321
322        let mut variants = vec![];
323
324        let span_end = loop {
325            let variant_name = match tokens.pop() {
326                Some((Token::Identifier(id), _)) => Ok(id),
327                Some((_, span)) => Err(util::ParseError(
328                    "Found non-identifier as data variant name".to_string(),
329                    Some(span),
330                )),
331                None => Err(util::ParseError(
332                    "Ran out of tokens while parsing data variant".to_string(),
333                    None,
334                )),
335            }?;
336
337            // parse variant body
338            expect_and_consume(tokens, Token::LParen)?;
339            let field_names = parse_params(tokens)?;
340
341            variants.push((variant_name, field_names));
342
343            // Determine whether we have another variant to parse or if this is the end
344            match tokens.pop() {
345                Some((Token::Pipe, _)) => continue,
346                Some((Token::End, span)) => break span.end,
347                Some((_, span)) => {
348                    return Err(util::ParseError(
349                        "Found bad token while parsing data variants".to_string(),
350                        Some(span),
351                    ))
352                }
353                None => {
354                    return Err(util::ParseError(
355                        "Ran out of tokens while parsing data variant".to_string(),
356                        None,
357                    ))
358                }
359            }
360        };
361
362        return Ok(Ast::new(
363            AstNode::DataDeclarationNode(data_name, variants),
364            SrcLoc {
365                span: span_start..span_end,
366            },
367        ));
368    }
369}
370
371pub struct MatchParselet {}
372impl PrefixParselet for MatchParselet {
373    fn parse(
374        &self,
375        tokens: &mut Vec<(Token, std::ops::Range<usize>)>,
376        current_token: (Token, std::ops::Range<usize>),
377        _is_top_level: bool,
378    ) -> Result<Ast, util::ParseError> {
379        let span_start = current_token.1.end;
380        let expression_to_match = parse_expr(tokens, 0, false)?;
381
382        expect_and_consume(tokens, Token::Colon)?;
383        // Initial pipe character is optional
384        expect_and_consume(tokens, Token::Pipe)?;
385
386        let mut branches = vec![];
387
388        let span_end = loop {
389            let branch_pattern = parse_pattern(tokens, 0)?;
390
391            // parse variant body
392            expect_and_consume(tokens, Token::FatArrow)?;
393            let branch_body = parse_expr(tokens, 0, false)?;
394
395            branches.push((branch_pattern, branch_body));
396
397            // Determine whether we have another variant to parse or if this is the end
398            match tokens.pop() {
399                Some((Token::Pipe, _)) => continue,
400                Some((Token::End, span)) => break span.end,
401                Some((token, span)) => {
402                    return Err(util::ParseError(
403                        format!(
404                            "Found bad token while parsing match expression: {:?}",
405                            token
406                        )
407                        .to_string(),
408                        Some(span),
409                    ))
410                }
411                None => {
412                    return Err(util::ParseError(
413                        "Ran out of tokens while parsing match expression".to_string(),
414                        None,
415                    ))
416                }
417            }
418        };
419
420        return Ok(Ast::new(
421            AstNode::MatchNode(Box::new(expression_to_match), branches),
422            SrcLoc {
423                span: span_start..span_end,
424            },
425        ));
426    }
427}
428
429pub struct OperatorParselet {
430    operator: BinOp,
431    is_left_associative: bool,
432}
433impl OperatorParselet {
434    pub fn new(op: BinOp, is_left_associative: bool) -> OperatorParselet {
435        OperatorParselet {
436            operator: op,
437            is_left_associative: is_left_associative,
438        }
439    }
440}
441impl InfixParselet for OperatorParselet {
442    fn parse(
443        &self,
444        tokens: &mut Vec<(Token, std::ops::Range<usize>)>,
445        left_node: Ast,
446        current_token: (Token, std::ops::Range<usize>),
447    ) -> Result<Ast, util::ParseError> {
448        let my_binding_power = parse::get_binding_power(&ast_op_to_token_op(&self.operator));
449        let right_node = parse::parse_expr(
450            tokens,
451            if self.is_left_associative {
452                my_binding_power
453            } else {
454                my_binding_power - 1
455            },
456            false,
457        )?;
458
459        return Ok(Ast::new(
460            AstNode::BinOpNode(self.operator, Box::new(left_node), Box::new(right_node)),
461            SrcLoc {
462                span: current_token.1,
463            },
464        ));
465    }
466}
467
468pub struct FunCallParselet {}
469impl PostfixParselet for FunCallParselet {
470    fn parse(
471        &self,
472        tokens: &mut Vec<(Token, std::ops::Range<usize>)>,
473        left_node: Ast,
474        _current_token: (Token, std::ops::Range<usize>),
475    ) -> Result<Ast, util::ParseError> {
476        let (args, span_end) = parse::parse_args(tokens)?;
477        let span_start = left_node.src_loc.span.start;
478        return Ok(Ast::new(
479            AstNode::FunCallNode(Box::new(left_node), args),
480            SrcLoc {
481                span: span_start..span_end,
482            },
483        ));
484    }
485}