1use ast::span::Spanned;
2use chumsky::{
3 combinator::{Map, OrNot, SeparatedBy, Then},
4 prelude::*,
5 primitive::Just,
6 Error,
7};
8use tokens::Token;
9use uuid::Uuid;
10
11pub(crate) fn parse_comment() -> impl Parser<Token, String, Error = Simple<Token>> + Clone {
12 filter_map(|span, token| match token {
13 Token::Comment(text) => Ok(text),
14 _ => Err(Simple::custom(span, "expected comment")),
15 })
16}
17
18pub(crate) fn parse_ident() -> impl Parser<Token, String, Error = Simple<Token>> + Clone {
19 filter_map(|span, token| match token {
20 Token::Ident(ident) => Ok(ident),
21 _ => Err(Simple::custom(span, "expected identifier")),
22 })
23}
24
25pub(crate) fn parse_uuid() -> impl Parser<Token, Uuid, Error = Simple<Token>> + Clone {
26 filter_map(|span, token| match token {
27 Token::Uuid(ident) => Ok(ident),
28 _ => Err(Simple::custom(span, "expected uuid")),
29 })
30}
31
32pub(crate) fn parse_op<U, O>(
33 op: impl Parser<Token, U, Error = Simple<Token>> + Clone,
34 item: impl Parser<Token, Spanned<O>, Error = Simple<Token>> + Clone,
35) -> impl Parser<Token, Vec<Spanned<O>>, Error = Simple<Token>> + Clone {
36 op.ignore_then(item.separated_by_comma())
37}
38
39pub(crate) fn parse_function<A, O, U>(
40 op: impl Parser<Token, U, Error = Simple<Token>> + Clone,
41 args: impl Parser<Token, Spanned<A>, Error = Simple<Token>> + Clone,
42 arrow: impl Parser<Token, U, Error = Simple<Token>> + Clone,
43 output: impl Parser<Token, Spanned<O>, Error = Simple<Token>> + Clone,
44) -> impl Parser<Token, (Vec<Spanned<A>>, Spanned<O>), Error = Simple<Token>> + Clone {
45 op.ignore_then(args.separated_by(just(Token::Comma)))
46 .then_ignore(arrow)
47 .then(output)
48}
49
50pub(crate) fn parse_collection<T>(
51 begin: Token,
52 item: impl Parser<Token, Spanned<T>, Error = Simple<Token>> + Clone,
53 end: Token,
54) -> impl Parser<Token, Vec<Spanned<T>>, Error = Simple<Token>> + Clone {
55 item.separated_by(just(Token::Comma))
56 .delimited_by(just(begin), just(end))
57}
58
59pub(crate) fn parse_typed<I, T>(
60 item: impl Parser<Token, Spanned<I>, Error = Simple<Token>> + Clone,
61 ty: impl Parser<Token, Spanned<T>, Error = Simple<Token>> + Clone,
62) -> impl Parser<Token, (Spanned<I>, Spanned<T>), Error = Simple<Token>> + Clone {
63 just(Token::FromHere)
64 .ignore_then(item)
65 .then_ignore(just(Token::TypeAnnotation))
66 .then(ty)
67}
68
69pub(crate) fn parse_attr<I, T>(
70 attr: impl Parser<Token, Spanned<I>, Error = Simple<Token>> + Clone,
71 item: impl Parser<Token, Spanned<T>, Error = Simple<Token>> + Clone,
72) -> impl Parser<Token, (Spanned<I>, Spanned<T>), Error = Simple<Token>> + Clone {
73 just(Token::Attribute).ignore_then(attr).in_().then(item)
74}
75
76type In<T, E, O> =
77 Map<Then<T, OrNot<Just<Token, Token, E>>>, fn((O, Option<Token>)) -> O, (O, Option<Token>)>;
78
79type SeparatedByComma<T, E, O> = Map<
80 OrNot<
81 Map<
82 Then<SeparatedBy<T, Just<Token, Token, E>, Token>, OrNot<Just<Token, Token, E>>>,
83 fn((Vec<O>, Option<Token>)) -> Vec<O>,
84 (Vec<O>, Option<Token>),
85 >,
86 >,
87 fn(Option<Vec<O>>) -> Vec<O>,
88 Option<Vec<O>>,
89>;
90
91type SeparatedByCommaAtLeastOne<T, E, O> = Map<
92 Then<SeparatedBy<T, Just<Token, Token, E>, Token>, OrNot<Just<Token, Token, E>>>,
93 fn((Vec<O>, Option<Token>)) -> Vec<O>,
94 (Vec<O>, Option<Token>),
95>;
96
97pub(crate) trait ParserExt<O>
98where
99 Self: Parser<Token, O> + Sized,
100{
101 fn in_(self) -> In<Self, Self::Error, O>;
102
103 fn separated_by_comma(self) -> SeparatedByComma<Self, Self::Error, O>;
104
105 fn separated_by_comma_at_least_one(self) -> SeparatedByCommaAtLeastOne<Self, Self::Error, O>;
106}
107
108impl<T: Parser<Token, O, Error = E>, O, E: Error<Token>> ParserExt<O> for T {
109 fn in_(self) -> In<Self, Self::Error, O>
110 where
111 Self: Sized,
112 {
113 self.then_ignore(just(Token::In).or_not())
114 }
115
116 fn separated_by_comma(self) -> SeparatedByComma<Self, Self::Error, O> {
117 self.separated_by_comma_at_least_one()
118 .or_not()
119 .map(|option| option.unwrap_or_default())
120 }
121
122 fn separated_by_comma_at_least_one(self) -> SeparatedByCommaAtLeastOne<Self, Self::Error, O> {
123 self.separated_by(just(Token::Comma))
124 .at_least(1)
125 .then_ignore(just(Token::Dot).or_not())
126 }
127}