1use super::{Delim, Token};
2use chumsky::prelude::*;
3use jaq_syn::path::{Opt, Part, Path};
4use jaq_syn::{Call, Spanned, Str};
5
6fn opt() -> impl Parser<Token, Opt, Error = Simple<Token>> + Clone {
7 just(Token::Question).or_not().map(|q| match q {
8 Some(_) => Opt::Optional,
9 None => Opt::Essential,
10 })
11}
12
13pub fn key<T, P>(expr: P) -> impl Parser<Token, Str<Spanned<T>>, Error = P::Error> + Clone
14where
15 T: From<Call<Spanned<T>>>,
16 P: Parser<Token, Spanned<T>, Error = Simple<Token>> + Clone,
17{
18 select! {
19 Token::Ident(s) => Str::from(s),
20 }
21 .or(super::string::str_(expr))
22 .labelled("object key")
23}
24
25fn index<T, P>(expr: P) -> impl Parser<Token, Part<Spanned<T>>, Error = P::Error> + Clone
26where
27 T: From<Str<Spanned<T>>> + From<Call<Spanned<T>>>,
28 P: Parser<Token, Spanned<T>, Error = Simple<Token>> + Clone,
29{
30 key(expr).map_with_span(|id, span| Part::Index((T::from(id), span)))
31}
32
33fn range<T, P>(expr: P) -> impl Parser<Token, Part<Spanned<T>>, Error = P::Error> + Clone
35where
36 P: Parser<Token, Spanned<T>, Error = Simple<Token>> + Clone,
37{
38 let e2 = just(Token::Colon).ignore_then(expr.clone().or_not());
39 let starts_with_expr = expr.clone().then(e2.or_not()).map(|(e1, e2)| match e2 {
40 None => Part::Index(e1),
41 Some(e2) => Part::Range(Some(e1), e2),
42 });
43 let starts_with_colon = just(Token::Colon)
44 .ignore_then(expr.clone())
45 .map(|e2| Part::Range(None, Some(e2)));
46
47 starts_with_expr
48 .or(starts_with_colon)
49 .or_not()
50 .map(|o| o.unwrap_or(Part::Range(None, None)))
51}
52
53pub fn path<T, P>(expr: P) -> impl Parser<Token, Path<T>, Error = P::Error> + Clone
55where
56 T: From<Str<Spanned<T>>> + From<Call<Spanned<T>>>,
57 P: Parser<Token, Spanned<T>, Error = Simple<Token>> + Clone,
58{
59 let range = Delim::Brack.around(range(expr.clone()));
60 let dot_index = just(Token::Dot).ignore_then(index(expr));
61 let dot_range = just(Token::Dot).or_not().ignore_then(range);
62 dot_index.or(dot_range).then(opt()).repeated()
63}
64
65pub fn part<T, P>(expr: P) -> impl Parser<Token, (Part<Spanned<T>>, Opt), Error = P::Error> + Clone
67where
68 T: From<Str<Spanned<T>>> + From<Call<Spanned<T>>>,
69 P: Parser<Token, Spanned<T>, Error = Simple<Token>> + Clone,
70{
71 let range = Delim::Brack.around(range(expr.clone()));
72 range.or(index(expr)).then(opt())
73}