Skip to main content

jql_parser/
parser.rs

1use winnow::{
2    Parser,
3    Result,
4    combinator::{
5        alt,
6        dispatch,
7        fail,
8        iterator,
9        peek,
10    },
11    token::any,
12};
13
14use crate::{
15    combinators::{
16        parse_flatten_operator,
17        parse_group_separator,
18        parse_keys_operator,
19        parse_lenses,
20        parse_pipe_in_operator,
21        parse_pipe_out_operator,
22        parse_selector,
23        parse_truncate_operator,
24        trim,
25    },
26    errors::JqlParserError,
27    tokens::{
28        Lens,
29        Token,
30        View,
31    },
32};
33
34/// Parses the provided input and map it to the first matching token.
35fn parse_fragment<'a>(input: &mut &'a str) -> Result<Token<'a>> {
36    trim(dispatch! {peek(any);
37        '[' | '"' | '{' => parse_selector,
38        '|' => {
39            alt((
40                parse_lenses.map(|lenses| {
41                    Token::LensSelector(
42                        lenses
43                            .into_iter()
44                            .map(|(tokens, value)| Lens(tokens, value))
45                            .collect(),
46                    )
47                }),
48                parse_pipe_in_operator.value(Token::PipeInOperator),
49            ))
50        },
51        '@' => parse_keys_operator.value(Token::KeyOperator),
52        '.' => parse_flatten_operator.value(Token::FlattenOperator),
53        '<' => parse_pipe_out_operator.value(Token::PipeOutOperator),
54        ',' => parse_group_separator.value(Token::GroupSeparator),
55        '!' => parse_truncate_operator.value(Token::TruncateOperator),
56        _ => fail
57    })
58    .parse_next(input)
59}
60
61/// Parses the provided input and returns a vector of `Tokens`.
62///
63/// # Errors
64///
65/// Returns a `JqlParserError` on failure.
66pub fn parse(input: &str) -> Result<Vec<Token<'_>>, JqlParserError> {
67    let mut input = input;
68    let mut parser_iterator = iterator(&mut input, parse_fragment);
69    let tokens = parser_iterator.collect::<Vec<Token>>();
70    let result: Result<_, _> = parser_iterator.finish();
71
72    match result {
73        Ok(()) => {
74            if !input.is_empty() {
75                return Err(JqlParserError::ParsingError {
76                    tokens: tokens.stringify(),
77                    unparsed: input.to_string(),
78                });
79            }
80
81            let truncate_count = tokens
82                .iter()
83                .filter(|&token| *token == Token::TruncateOperator)
84                .count();
85
86            if truncate_count > 1
87                || (truncate_count == 1 && tokens.last() != Some(&Token::TruncateOperator))
88            {
89                return Err(JqlParserError::TruncateError(tokens.stringify()));
90            }
91
92            Ok(tokens)
93        }
94        Err(_) => Err(JqlParserError::UnknownError),
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use super::{
101        parse,
102        parse_fragment,
103    };
104    use crate::{
105        errors::JqlParserError,
106        tokens::{
107            Index,
108            Lens,
109            LensValue,
110            Range,
111            Token,
112            View,
113        },
114    };
115
116    #[test]
117    fn check_array_index_selector() {
118        assert_eq!(
119            parse_fragment(&mut "[0,1,2]"),
120            Ok(Token::ArrayIndexSelector(vec![
121                Index(0),
122                Index(1),
123                Index(2)
124            ]))
125        );
126        assert_eq!(
127            parse_fragment(&mut " [ 0 , 1 , 2 ] "),
128            Ok(Token::ArrayIndexSelector(vec![
129                Index(0),
130                Index(1),
131                Index(2)
132            ]))
133        );
134    }
135
136    #[test]
137    fn check_array_range_selector() {
138        assert_eq!(
139            parse_fragment(&mut "[0:2]"),
140            Ok(Token::ArrayRangeSelector(Range(
141                Some(Index(0)),
142                Some(Index(2))
143            )))
144        );
145        assert_eq!(
146            parse_fragment(&mut "[:2]"),
147            Ok(Token::ArrayRangeSelector(Range(None, Some(Index(2)))))
148        );
149        assert_eq!(
150            parse_fragment(&mut "[0:]"),
151            Ok(Token::ArrayRangeSelector(Range(Some(Index(0)), None)))
152        );
153        assert_eq!(
154            parse_fragment(&mut "[:]"),
155            Ok(Token::ArrayRangeSelector(Range(None, None)))
156        );
157    }
158
159    #[test]
160    fn check_key_selector() {
161        assert_eq!(
162            parse_fragment(&mut r#""one""#),
163            Ok(Token::KeySelector("one".into()))
164        );
165        assert_eq!(
166            parse_fragment(&mut r#" "one" "#),
167            Ok(Token::KeySelector("one".into()))
168        );
169    }
170
171    #[test]
172    fn check_multi_key_selector() {
173        assert_eq!(
174            parse_fragment(&mut r#"{"one","two","three"}"#),
175            Ok(Token::MultiKeySelector(vec![
176                "one".into(),
177                "two".into(),
178                "three".into()
179            ]))
180        );
181        assert_eq!(
182            parse_fragment(&mut r#" { "one", "two" , "three" } "#),
183            Ok(Token::MultiKeySelector(vec![
184                "one".into(),
185                "two".into(),
186                "three".into()
187            ]))
188        );
189    }
190
191    #[test]
192    fn check_object_index_selector() {
193        assert_eq!(
194            parse_fragment(&mut "{0,1,2}"),
195            Ok(Token::ObjectIndexSelector(vec![
196                Index(0),
197                Index(1),
198                Index(2)
199            ]))
200        );
201        assert_eq!(
202            parse_fragment(&mut " { 0 , 1 , 2 } "),
203            Ok(Token::ObjectIndexSelector(vec![
204                Index(0),
205                Index(1),
206                Index(2)
207            ]))
208        );
209    }
210
211    #[test]
212    fn check_object_range_selector() {
213        assert_eq!(
214            parse_fragment(&mut "{0:2}"),
215            Ok(Token::ObjectRangeSelector(Range(
216                Some(Index(0)),
217                Some(Index(2))
218            )))
219        );
220        assert_eq!(
221            parse_fragment(&mut "{:2}"),
222            Ok(Token::ObjectRangeSelector(Range(None, Some(Index(2)))))
223        );
224        assert_eq!(
225            parse_fragment(&mut "{0:}"),
226            Ok(Token::ObjectRangeSelector(Range(Some(Index(0)), None)))
227        );
228        assert_eq!(
229            parse_fragment(&mut "{:}"),
230            Ok(Token::ObjectRangeSelector(Range(None, None)))
231        );
232    }
233
234    #[test]
235    fn check_lens_selector() {
236        assert_eq!(
237            parse_fragment(&mut r#"|={"abc""c","bcd""d"=123,"efg"=null,"hij"="test"}"#),
238            Ok(Token::LensSelector(vec![
239                Lens(
240                    vec![
241                        Token::KeySelector("abc".into()),
242                        Token::KeySelector("c".into())
243                    ],
244                    None
245                ),
246                Lens(
247                    vec![
248                        Token::KeySelector("bcd".into()),
249                        Token::KeySelector("d".into())
250                    ],
251                    Some(LensValue::Number(123))
252                ),
253                Lens(
254                    vec![Token::KeySelector("efg".into())],
255                    Some(LensValue::Null)
256                ),
257                Lens(
258                    vec![Token::KeySelector("hij".into())],
259                    Some(LensValue::String("test".into()))
260                ),
261            ]))
262        );
263    }
264
265    #[test]
266    fn check_flatten_operator() {
267        assert_eq!(parse_fragment(&mut ".."), Ok(Token::FlattenOperator));
268        assert_eq!(parse_fragment(&mut " .. "), Ok(Token::FlattenOperator));
269    }
270
271    #[test]
272    fn check_pipe_in_operator() {
273        assert_eq!(parse_fragment(&mut "|>"), Ok(Token::PipeInOperator));
274        assert_eq!(parse_fragment(&mut " |> "), Ok(Token::PipeInOperator));
275    }
276
277    #[test]
278    fn check_pipe_out_operator() {
279        assert_eq!(parse_fragment(&mut "<|"), Ok(Token::PipeOutOperator));
280        assert_eq!(parse_fragment(&mut " <| "), Ok(Token::PipeOutOperator));
281    }
282
283    #[test]
284    fn check_truncate_operator() {
285        assert_eq!(parse_fragment(&mut "!"), Ok(Token::TruncateOperator));
286        assert_eq!(parse_fragment(&mut " ! "), Ok(Token::TruncateOperator));
287    }
288
289    #[test]
290    fn check_group_separator() {
291        assert_eq!(parse_fragment(&mut ","), Ok(Token::GroupSeparator));
292        assert_eq!(parse_fragment(&mut " , "), Ok(Token::GroupSeparator));
293    }
294
295    #[test]
296    fn check_full_parser() {
297        assert_eq!(
298            parse(r#""this"[9,0]"#),
299            Ok(vec![
300                Token::KeySelector("this".into()),
301                Token::ArrayIndexSelector(vec![Index(9), Index(0)])
302            ]),
303        );
304        assert_eq!(
305            parse("[9,0]nope"),
306            Err(JqlParserError::ParsingError {
307                tokens: [Token::ArrayIndexSelector(vec![Index(9), Index(0)])].stringify(),
308                unparsed: "nope".to_string(),
309            })
310        );
311        assert_eq!(
312            parse(r#""this"[9,0]|>"some"<|"ok"..!"#),
313            Ok(vec![
314                Token::KeySelector("this".into()),
315                Token::ArrayIndexSelector(vec![Index(9), Index(0)]),
316                Token::PipeInOperator,
317                Token::KeySelector("some".into()),
318                Token::PipeOutOperator,
319                Token::KeySelector("ok".into()),
320                Token::FlattenOperator,
321                Token::TruncateOperator
322            ]),
323        );
324        assert_eq!(
325            parse(r#""a"!"b""#),
326            Err(JqlParserError::TruncateError(
327                [
328                    Token::KeySelector("a".into()),
329                    Token::TruncateOperator,
330                    Token::KeySelector("b".into())
331                ]
332                .stringify()
333            ))
334        );
335    }
336}