deskc_parser/
common.rs

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}