aiken_lang/parser/pattern/
list.rs1use chumsky::prelude::*;
2
3use crate::{
4 ast::{self, UntypedPattern},
5 parser::{
6 error::{self, ParseError},
7 token::Token,
8 },
9};
10
11pub fn parser(
12 expression: Recursive<'_, Token, UntypedPattern, ParseError>,
13) -> impl Parser<Token, UntypedPattern, Error = ParseError> + '_ {
14 just(Token::LeftSquare)
15 .ignore_then(expression.clone().separated_by(just(Token::Comma)))
16 .then(choice((
17 just(Token::Comma).ignore_then(
18 just(Token::DotDot)
19 .ignore_then(expression.clone().or_not())
20 .or_not(),
21 ),
22 just(Token::Comma).ignored().or_not().map(|_| None),
23 )))
24 .then_ignore(just(Token::RightSquare))
25 .validate(|(elements, tail), span: ast::Span, emit| {
26 if elements.is_empty() && tail.is_some() {
28 emit(ParseError::expected_input_found(
29 span,
30 None,
31 Some(error::Pattern::SpreadNoSubject),
32 ));
33 }
34
35 let tail = match tail {
36 Some(Some(pat @ (UntypedPattern::Var { .. } | UntypedPattern::Discard { .. }))) => {
38 Some(pat)
39 }
40 Some(Some(pat)) => {
41 emit(ParseError::expected_input_found(
42 pat.location(),
43 None,
44 Some(error::Pattern::Match),
45 ));
46
47 Some(pat)
48 }
49 Some(None) => Some(UntypedPattern::Discard {
51 location: ast::Span {
52 start: span.end - 1,
53 end: span.end,
54 },
55 name: "_".to_string(),
56 }),
57 None => None,
59 };
60
61 UntypedPattern::List {
62 location: span,
63 elements,
64 tail: tail.map(Box::new),
65 }
66 })
67}