platelet/
expression_parser.rs

1use serde_json::Number;
2use std::collections::HashMap;
3use winnow::combinator::opt;
4
5use winnow::ascii;
6use winnow::error::{ContextError, ParseError};
7use winnow::prelude::*;
8use winnow::{
9    combinator::alt,
10    combinator::cut_err,
11    combinator::{delimited, preceded, separated_pair, terminated},
12    combinator::{repeat, separated},
13    error::ParserError,
14    token::{any, none_of, take, take_while},
15};
16
17pub(crate) fn expr<'a>(
18    input: &'a mut &str,
19) -> Result<Expression, ParseError<&'a str, ContextError>> {
20    delimited(ws, expression, ws).parse(input)
21}
22
23#[derive(Debug, PartialEq, Clone)]
24pub(crate) enum Expression {
25    Indexed(Box<(Expression, Expression)>),
26    BinaryOperation(Box<(Expression, BinaryOperator, Expression)>),
27    FunctionCall(Box<(String, Expression)>),
28    UnaryOperation(Box<(UnaryOperator, Expression)>),
29    Conditional(Box<(Expression, Expression, Expression)>),
30    Null,
31    Boolean(bool),
32    Str(String),
33    Num(Number),
34    Array(Vec<Expression>),
35    Object(HashMap<String, Expression>),
36    Identifier(String),
37}
38
39#[derive(Debug, PartialEq, Clone)]
40pub(crate) enum BinaryOperator {
41    Add,
42    Subtract,
43    Multiply,
44    Divide,
45    Modulo,
46    EqualTo,
47    NotEqualTo,
48    GreaterThan,
49    GreterThanOrEqualTo,
50    LessThan,
51    LessThanOrEqualTo,
52    Or,
53    And,
54}
55
56#[derive(Debug, PartialEq, Clone)]
57pub(crate) enum UnaryOperator {
58    Not,
59}
60
61pub(crate) fn expression(input: &mut &str) -> PResult<Expression> {
62    conditional_expression.parse_next(input)
63}
64
65fn conditional_expression(input: &mut &str) -> PResult<Expression> {
66    let cond = or_expression.parse_next(input)?;
67    if let Ok(Some((x, y))) = opt((
68        preceded((ws, '?', ws), expression),
69        preceded((ws, ':', ws), conditional_expression),
70    ))
71    .parse_next(input)
72    {
73        Ok(Expression::Conditional(Box::new((cond, x, y))))
74    } else {
75        Ok(cond)
76    }
77}
78
79fn or_expression(input: &mut &str) -> PResult<Expression> {
80    let x = and_expression.parse_next(input)?;
81    if let Ok(op) = delimited(ws, "||".value(BinaryOperator::Or), ws).parse_next(input) {
82        let y = or_expression(input)?;
83        return Ok(Expression::BinaryOperation(Box::new((x, op, y))));
84    } else {
85        return Ok(x);
86    }
87}
88
89fn and_expression(input: &mut &str) -> PResult<Expression> {
90    let x = equality_operation.parse_next(input)?;
91    if let Ok(op) = delimited(ws, "&&".value(BinaryOperator::And), ws).parse_next(input) {
92        let y = and_expression(input)?;
93        return Ok(Expression::BinaryOperation(Box::new((x, op, y))));
94    } else {
95        return Ok(x);
96    }
97}
98
99fn equality_operation(input: &mut &str) -> PResult<Expression> {
100    let x = comparison_expression.parse_next(input)?;
101    if let Ok(op) = delimited(
102        ws,
103        alt((
104            "==".value(BinaryOperator::EqualTo),
105            "!=".value(BinaryOperator::NotEqualTo),
106        )),
107        ws,
108    )
109    .parse_next(input)
110    {
111        let y = equality_operation(input)?;
112        return Ok(Expression::BinaryOperation(Box::new((x, op, y))));
113    } else {
114        return Ok(x);
115    }
116}
117
118fn comparison_expression(input: &mut &str) -> PResult<Expression> {
119    let x = modulo_expression.parse_next(input)?;
120    if let Ok(op) = delimited(
121        ws,
122        alt((
123            ">=".value(BinaryOperator::GreterThanOrEqualTo),
124            ">".value(BinaryOperator::GreaterThan),
125            "<=".value(BinaryOperator::LessThanOrEqualTo),
126            "<".value(BinaryOperator::LessThan),
127        )),
128        ws,
129    )
130    .parse_next(input)
131    {
132        let y = comparison_expression(input)?;
133        return Ok(Expression::BinaryOperation(Box::new((x, op, y))));
134    } else {
135        return Ok(x);
136    }
137}
138
139fn modulo_expression(input: &mut &str) -> PResult<Expression> {
140    let x = additive_expression.parse_next(input)?;
141    if let Ok(op) = delimited(ws, "%".value(BinaryOperator::Modulo), ws).parse_next(input) {
142        let y = modulo_expression(input)?;
143        return Ok(Expression::BinaryOperation(Box::new((x, op, y))));
144    } else {
145        return Ok(x);
146    }
147}
148
149fn additive_expression(input: &mut &str) -> PResult<Expression> {
150    let x = multiplicative_expression.parse_next(input)?;
151    if let Ok(op) = delimited(
152        ws,
153        alt((
154            "+".value(BinaryOperator::Add),
155            "-".value(BinaryOperator::Subtract),
156        )),
157        ws,
158    )
159    .parse_next(input)
160    {
161        let y = additive_expression(input)?;
162        return Ok(Expression::BinaryOperation(Box::new((x, op, y))));
163    } else {
164        return Ok(x);
165    }
166}
167
168fn multiplicative_expression(input: &mut &str) -> PResult<Expression> {
169    let x = unary_expression.parse_next(input)?;
170    if let Ok(op) = delimited(
171        ws,
172        alt((
173            "*".value(BinaryOperator::Multiply),
174            "/".value(BinaryOperator::Divide),
175        )),
176        ws,
177    )
178    .parse_next(input)
179    {
180        let y = multiplicative_expression(input)?;
181        return Ok(Expression::BinaryOperation(Box::new((x, op, y))));
182    } else {
183        return Ok(x);
184    }
185}
186
187fn unary_expression(input: &mut &str) -> PResult<Expression> {
188    if let Ok(exp) = preceded(('!', ws), indexed_expression).parse_next(input) {
189        return Ok(Expression::UnaryOperation(Box::new((
190            UnaryOperator::Not,
191            exp,
192        ))));
193    } else {
194        return indexed_expression.parse_next(input);
195    }
196}
197
198fn indexed_expression(input: &mut &str) -> PResult<Expression> {
199    let mut exp = primary_expression.parse_next(input)?;
200    while let Ok(index) = preceded(
201        ws,
202        alt((
203            delimited('[', delimited(ws, expression, ws), ']'),
204            preceded(('.', ws), identifier.map(Expression::Str)),
205        )),
206    )
207    .parse_next(input)
208    {
209        exp = Expression::Indexed(Box::new((exp, index)));
210    }
211    return Ok(exp);
212}
213
214fn primary_expression(input: &mut &str) -> PResult<Expression> {
215    alt((
216        delimited('(', delimited(ws, expression, ws), ')'),
217        null.value(Expression::Null),
218        boolean.map(Expression::Boolean),
219        string.map(Expression::Str),
220        number.map(Expression::Num),
221        array.map(Expression::Array),
222        object.map(Expression::Object),
223        function_call.map(Expression::FunctionCall),
224        identifier.map(Expression::Identifier),
225    ))
226    .parse_next(input)
227}
228
229fn function_call(input: &mut &str) -> PResult<Box<(String, Expression)>> {
230    separated_pair(identifier, ws, delimited(('(', ws), expression, (ws, ')')))
231        .map(|(id, arg)| Box::new((id, arg)))
232        .parse_next(input)
233}
234
235pub(crate) fn number(input: &mut &str) -> PResult<Number> {
236    (|input: &mut &str| {
237        let s = recognize_float(input)?;
238        categorize_num(s).ok_or_else(|| {
239            winnow::error::ErrMode::from_error_kind(input, winnow::error::ErrorKind::Verify)
240        })
241    })
242    .parse_next(input)
243}
244
245fn categorize_num(s: &str) -> Option<Number> {
246    if s.contains('.') || s.contains('e') || s.contains('E') {
247        return s.parse().map(|x: f64| Number::from_f64(x).unwrap()).ok();
248    } else if s.starts_with('-') {
249        return s.parse::<i32>().map(|x| Number::from(x)).ok();
250    } else {
251        return s.parse::<u32>().map(|x| Number::from(x)).ok();
252    }
253}
254
255fn recognize_float<'a>(input: &mut &'a str) -> PResult<&'a str> {
256    (
257        opt(winnow::token::one_of(['+', '-'])),
258        alt((
259            (ascii::digit1, opt(('.', opt(ascii::digit1)))).void(),
260            ('.', ascii::digit1).void(),
261        )),
262        opt((
263            winnow::token::one_of(['e', 'E']),
264            opt(winnow::token::one_of(['+', '-'])),
265            cut_err(ascii::digit1),
266        )),
267    )
268        .recognize()
269        .parse_next(input)
270}
271
272fn null<'s>(input: &mut &'s str) -> PResult<&'s str> {
273    "null".parse_next(input)
274}
275
276fn boolean(input: &mut &str) -> PResult<bool> {
277    alt(("true".value(true), "false".value(false))).parse_next(input)
278}
279fn string(input: &mut &str) -> PResult<String> {
280    alt((single_string, double_string)).parse_next(input)
281}
282
283fn double_string(input: &mut &str) -> PResult<String> {
284    preceded(
285        '\"',
286        cut_err(terminated(
287            repeat(0.., character).fold(String::new, |mut string, c| {
288                string.push(c);
289                string
290            }),
291            '\"',
292        )),
293    )
294    .parse_next(input)
295}
296
297fn single_string(input: &mut &str) -> PResult<String> {
298    preceded(
299        '\'',
300        cut_err(terminated(
301            repeat(0.., character).fold(String::new, |mut string, c| {
302                string.push(c);
303                string
304            }),
305            '\'',
306        )),
307    )
308    .parse_next(input)
309}
310
311pub(crate) fn identifier<'s>(input: &'s mut &str) -> PResult<String> {
312    take_while(1.., ('a'..='z', 'A'..='Z', '_'))
313        .parse_next(input)
314        .map(|s| s.to_string())
315}
316
317/// You can mix the above declarative parsing with an imperative style to handle more unique cases,
318/// like escaping
319fn character(input: &mut &str) -> PResult<char> {
320    let c = none_of(['\"', '\'']).parse_next(input)?;
321    if c == '\\' {
322        alt((
323            any.verify_map(|c| {
324                Some(match c {
325                    '"' | '\\' | '/' => c,
326                    'b' => '\x08',
327                    'f' => '\x0C',
328                    'n' => '\n',
329                    'r' => '\r',
330                    't' => '\t',
331                    _ => return None,
332                })
333            }),
334            preceded('u', unicode_escape),
335        ))
336        .parse_next(input)
337    } else {
338        Ok(c)
339    }
340}
341
342fn unicode_escape<'s>(input: &mut &'s str) -> PResult<char> {
343    alt((
344        // Not a surrogate
345        u16_hex
346            .verify(|cp| !(0xD800..0xE000).contains(cp))
347            .map(|cp| cp as u32),
348        // See https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF for details
349        separated_pair(u16_hex, "\\u", u16_hex)
350            .verify(|(high, low)| (0xD800..0xDC00).contains(high) && (0xDC00..0xE000).contains(low))
351            .map(|(high, low)| {
352                let high_ten = (high as u32) - 0xD800;
353                let low_ten = (low as u32) - 0xDC00;
354                (high_ten << 10) + low_ten + 0x10000
355            }),
356    ))
357    .verify_map(
358        // Could be probably replaced with .unwrap() or _unchecked due to the verify checks
359        std::char::from_u32,
360    )
361    .parse_next(input)
362}
363
364fn u16_hex(input: &mut &str) -> PResult<u16> {
365    take(4usize)
366        .verify_map(|s| u16::from_str_radix(s, 16).ok())
367        .parse_next(input)
368}
369
370/// Some combinators, like `separated` or `repeat`, will call a parser repeatedly,
371/// accumulating results in a `Vec`, until it encounters an error.
372/// If you want more control on the parser application, check out the `iterator`
373/// combinator (cf `examples/iterator.rs`)
374fn array(input: &mut &str) -> PResult<Vec<Expression>> {
375    preceded(
376        ('[', ws),
377        cut_err(terminated(
378            separated(0.., expression, (ws, ',', ws)),
379            (ws, ']'),
380        )),
381    )
382    .parse_next(input)
383}
384
385fn object(input: &mut &str) -> PResult<HashMap<String, Expression>> {
386    preceded(
387        ('{', ws),
388        cut_err(terminated(
389            separated(0.., key_value, (ws, ',', ws)),
390            (ws, '}'),
391        )),
392    )
393    .parse_next(input)
394}
395
396fn key_value(input: &mut &str) -> PResult<(String, Expression)> {
397    separated_pair(string, cut_err((ws, ':', ws)), expression).parse_next(input)
398}
399
400pub(crate) fn ws<'s>(input: &mut &'s str) -> PResult<&'s str> {
401    take_while(0.., WS).parse_next(input)
402}
403
404const WS: &[char] = &[' ', '\t', '\r', '\n'];
405
406#[cfg(test)]
407mod test {
408    use super::*;
409
410    #[test]
411    fn json_string() {
412        assert_eq!(string.parse_peek("\"\""), Ok(("", "".to_owned())));
413        assert_eq!(string.parse_peek("\"abc\""), Ok(("", "abc".to_owned())));
414        assert_eq!(
415            string.parse_peek("\"abc\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0001\\u2014\u{2014}def\""),
416            Ok(("", "abc\"\\/\x08\x0C\n\r\t\x01β€”β€”def".to_owned())),
417        );
418        assert_eq!(
419            string.parse_peek("\"\\uD83D\\uDE10\""),
420            Ok(("", "😐".to_owned()))
421        );
422
423        assert!(string.parse_peek("\"").is_err());
424        assert!(string.parse_peek("\"abc").is_err());
425        assert!(string.parse_peek("\"\\\"").is_err());
426        assert!(string.parse_peek("\"\\u123\"").is_err());
427        assert!(string.parse_peek("\"\\uD800\"").is_err());
428        assert!(string.parse_peek("\"\\uD800\\uD800\"").is_err());
429        assert!(string.parse_peek("\"\\uDC00\"").is_err());
430    }
431
432    #[test]
433    fn json_object() {
434        use Expression::{Num, Str};
435
436        let input = r#"{"a":42,"b":"x"}"#;
437
438        let expected = Expression::Object(
439            vec![
440                ("a".to_owned(), Num(42.into())),
441                ("b".to_owned(), Str("x".to_owned())),
442            ]
443            .into_iter()
444            .collect(),
445        );
446
447        assert_eq!(expression.parse_peek(input), Ok(("", expected)));
448    }
449
450    #[test]
451    fn json_array() {
452        use Expression::{Num, Str};
453
454        let input = r#"[42,"x"]"#;
455
456        let expected = Expression::Array(vec![Num(42.into()), Str("x".to_owned())]);
457
458        assert_eq!(expression.parse_peek(input), Ok(("", expected)));
459    }
460
461    #[test]
462    fn json_whitespace() {
463        use Expression::{Array, Boolean, Null, Num, Object, Str};
464
465        let input = r#"{
466      "null" : null,
467      "true"  :true ,
468      "false":  false  ,
469      "number" : 123e4 ,
470      "string" : " abc 123 " ,
471      "array" : [ false , 1 , "two" ] ,
472      "object" : { "a" : 1.0 , "b" : "c" } ,
473      "empty_array" : [  ] ,
474      "empty_object" : {   }
475    }"#;
476
477        assert_eq!(
478            expression.parse_peek(input),
479            Ok((
480                "",
481                Expression::Object(
482                    vec![
483                        ("null".to_owned(), Null),
484                        ("true".to_owned(), Boolean(true)),
485                        ("false".to_owned(), Boolean(false)),
486                        ("number".to_owned(), Num(Number::from_f64(123e4).unwrap())),
487                        ("string".to_owned(), Str(" abc 123 ".to_owned())),
488                        (
489                            "array".to_owned(),
490                            Array(vec![Boolean(false), Num(1.into()), Str("two".to_owned())])
491                        ),
492                        (
493                            "object".to_owned(),
494                            Object(
495                                vec![
496                                    ("a".to_owned(), Num(Number::from_f64(1.0).unwrap())),
497                                    ("b".to_owned(), Str("c".to_owned())),
498                                ]
499                                .into_iter()
500                                .collect()
501                            )
502                        ),
503                        ("empty_array".to_owned(), Array(vec![]),),
504                        ("empty_object".to_owned(), Object(HashMap::new()),),
505                    ]
506                    .into_iter()
507                    .collect()
508                )
509            ))
510        );
511    }
512
513    #[test]
514    fn indexed_expressions() {
515        use Expression::{Num, Object};
516
517        let input = r#"{ "z": 1 }[0]"#;
518
519        assert_eq!(
520            expression.parse_peek(input),
521            Ok((
522                "",
523                Expression::Indexed(Box::new((
524                    Object(vec![("z".to_owned(), Num(1.into()))].into_iter().collect()),
525                    Num(0.into())
526                )))
527            ))
528        )
529    }
530
531    #[test]
532    fn indexed_expressions_2() {
533        use Expression::{Num, Object};
534
535        let input = r#"{ "z": 1 } [ 0 ]"#;
536
537        assert_eq!(
538            expression.parse_peek(input),
539            Ok((
540                "",
541                Expression::Indexed(Box::new((
542                    Object(vec![("z".to_owned(), Num(1.into()))].into_iter().collect()),
543                    Num(0.into())
544                )))
545            ))
546        )
547    }
548
549    #[test]
550    fn multi_identifiers_0() {
551        let input = r#"window"#;
552
553        assert_eq!(identifier.parse_peek(input), Ok(("", "window".to_owned())))
554    }
555
556    #[test]
557    fn expression_multi_identifier() {
558        let input = r#"props.user.name"#;
559
560        assert_eq!(
561            expression.parse_peek(input),
562            Ok((
563                "",
564                Expression::Indexed(Box::new((
565                    Expression::Indexed(Box::new((
566                        Expression::Identifier("props".to_owned()),
567                        Expression::Str("user".to_owned())
568                    ))),
569                    Expression::Str("name".to_owned())
570                ))),
571            ))
572        )
573    }
574
575    #[test]
576    fn expression_or() {
577        use Expression::{BinaryOperation, Num};
578        let input = r#"props.user.name || 1.0"#;
579
580        assert_eq!(
581            expression.parse_peek(input),
582            Ok((
583                "",
584                BinaryOperation(Box::new((
585                    Expression::Indexed(Box::new((
586                        Expression::Indexed(Box::new((
587                            Expression::Identifier("props".to_owned()),
588                            Expression::Str("user".to_owned())
589                        ))),
590                        Expression::Str("name".to_owned())
591                    ))),
592                    BinaryOperator::Or,
593                    Num(Number::from_f64(1.0).unwrap())
594                )))
595            ))
596        )
597    }
598
599    #[test]
600    fn expression_and() {
601        use Expression::{Array, BinaryOperation, Indexed, Num, Object};
602        let input = r#"[1] && {}[3]"#;
603
604        assert_eq!(
605            expression.parse_peek(input),
606            Ok((
607                "",
608                BinaryOperation(Box::new((
609                    Array(vec![Num(1.into())]),
610                    BinaryOperator::And,
611                    Indexed(Box::new((Object(HashMap::new()), Num(3.into()))))
612                )))
613            ))
614        )
615    }
616
617    #[test]
618    fn expression_add() {
619        use Expression::{BinaryOperation, Identifier, Num};
620        let input = r#"name + 1.0"#;
621
622        assert_eq!(
623            expression.parse_peek(input),
624            Ok((
625                "",
626                BinaryOperation(Box::new((
627                    Identifier("name".to_owned()),
628                    BinaryOperator::Add,
629                    Num(Number::from_f64(1.0).unwrap())
630                )))
631            ))
632        )
633    }
634
635    #[test]
636    fn expression_eq() {
637        use Expression::{BinaryOperation, Identifier, Str};
638        let input = r#"props == """#;
639
640        assert_eq!(
641            expression.parse_peek(input),
642            Ok((
643                "",
644                BinaryOperation(Box::new((
645                    Identifier("props".to_owned()),
646                    BinaryOperator::EqualTo,
647                    Str("".to_owned())
648                )))
649            ))
650        )
651    }
652
653    #[test]
654    fn expression_indexed() {
655        use Expression::{BinaryOperation, Indexed, Object, Str};
656        let input = r#"{ "hello": "world" }["hell" + "o"]"#;
657
658        assert_eq!(
659            expression.parse_peek(input),
660            Ok((
661                "",
662                Indexed(Box::new((
663                    Object(HashMap::from([(
664                        "hello".to_owned(),
665                        Str("world".to_owned())
666                    )])),
667                    BinaryOperation(Box::new((
668                        Str("hell".to_owned()),
669                        BinaryOperator::Add,
670                        Str("o".to_owned())
671                    )))
672                )))
673            ))
674        )
675    }
676
677    #[test]
678    fn expression_iif() {
679        use Expression::{BinaryOperation, Conditional, Num};
680        let input = r#"1 > 2 ? 1 : 2"#;
681
682        assert_eq!(
683            expression.parse_peek(input),
684            Ok((
685                "",
686                Conditional(Box::new((
687                    BinaryOperation(Box::new((
688                        Num(1.into()),
689                        BinaryOperator::GreaterThan,
690                        Num(2.into())
691                    ))),
692                    Num(1.into()),
693                    Num(2.into())
694                )))
695            ))
696        )
697    }
698
699    #[test]
700    fn expression_bidmas() {
701        use Expression::{BinaryOperation, Num};
702        let input = r#"(9 + 3) / 2 == 6"#;
703
704        assert_eq!(
705            expression.parse_peek(input),
706            Ok((
707                "",
708                BinaryOperation(Box::new((
709                    BinaryOperation(Box::new((
710                        BinaryOperation(Box::new((
711                            Num(9.into()),
712                            BinaryOperator::Add,
713                            Num(3.into())
714                        ))),
715                        BinaryOperator::Divide,
716                        Num(2.into())
717                    ))),
718                    BinaryOperator::EqualTo,
719                    Num(6.into())
720                )))
721            ))
722        )
723    }
724
725    #[test]
726    fn unary_not() {
727        let input = r#"!this"#;
728
729        assert_eq!(
730            expression.parse_peek(input),
731            Ok((
732                "",
733                Expression::UnaryOperation(Box::new((
734                    UnaryOperator::Not,
735                    Expression::Identifier("this".to_owned())
736                )))
737            ))
738        )
739    }
740
741    #[test]
742    fn expression_mod() {
743        let input = r#"1%3"#;
744
745        assert_eq!(
746            expression.parse_peek(input),
747            Ok((
748                "",
749                Expression::BinaryOperation(Box::new((
750                    Expression::Num(1.into()),
751                    BinaryOperator::Modulo,
752                    Expression::Num(3.into())
753                )))
754            ))
755        )
756    }
757
758    #[test]
759    fn expression_conditional_order_of_ops() {
760        let input = r#"1 < 2 == true"#;
761
762        assert_eq!(
763            expression.parse_peek(input),
764            Ok((
765                "",
766                Expression::BinaryOperation(Box::new((
767                    Expression::BinaryOperation(Box::new((
768                        Expression::Num(1.into()),
769                        BinaryOperator::LessThan,
770                        Expression::Num(2.into())
771                    ))),
772                    BinaryOperator::EqualTo,
773                    Expression::Boolean(true.into())
774                )))
775            ))
776        )
777    }
778
779    #[test]
780    fn expression_in_object() {
781        let input = r#"{"hello": [ 1 * 2 ] }"#;
782        assert_eq!(
783            expression.parse_peek(input),
784            Ok((
785                "",
786                Expression::Object(HashMap::from([(
787                    "hello".to_owned(),
788                    Expression::Array(vec![Expression::BinaryOperation(Box::new((
789                        Expression::Num(1.into()),
790                        BinaryOperator::Multiply,
791                        Expression::Num(2.into())
792                    )))])
793                )]))
794            ))
795        )
796    }
797
798    #[test]
799    fn single_quote_strings() {
800        let input = r#"{'hello': 'worl' + "d"}"#;
801        assert_eq!(
802            expression.parse_peek(input),
803            Ok((
804                "",
805                Expression::Object(HashMap::from([(
806                    "hello".to_owned(),
807                    Expression::BinaryOperation(Box::new((
808                        Expression::Str("worl".into()),
809                        BinaryOperator::Add,
810                        Expression::Str("d".into()),
811                    )))
812                )]))
813            ))
814        )
815    }
816
817    #[test]
818    fn indexed_exp() {
819        let input = r#"data.people[0].age"#;
820        assert_eq!(
821            expression.parse_peek(input),
822            Ok((
823                "",
824                Expression::Indexed(Box::new((
825                    (Expression::Indexed(Box::new((
826                        Expression::Indexed(Box::new((
827                            Expression::Identifier("data".to_owned()),
828                            Expression::Str("people".to_owned())
829                        ))),
830                        Expression::Num(0.into())
831                    )))),
832                    Expression::Str("age".to_owned())
833                )))
834            ))
835        )
836    }
837
838    #[test]
839    fn indexed_exp_no_dots() {
840        let input = r#"data["people"][0]["age"]"#;
841        assert_eq!(
842            expression.parse_peek(input),
843            Ok((
844                "",
845                Expression::Indexed(Box::new((
846                    (Expression::Indexed(Box::new((
847                        Expression::Indexed(Box::new((
848                            Expression::Identifier("data".to_owned()),
849                            Expression::Str("people".to_owned())
850                        ))),
851                        Expression::Num(0.into())
852                    )))),
853                    Expression::Str("age".to_owned())
854                )))
855            ))
856        )
857    }
858
859    #[test]
860    fn function_call() {
861        let input = r#"format_money({"currency": "gbp", "value": 100})"#;
862        assert_eq!(
863            expression.parse_peek(input),
864            Ok((
865                "",
866                Expression::FunctionCall(Box::new((
867                    "format_money".into(),
868                    Expression::Object(HashMap::from([
869                        ("currency".into(), Expression::Str("gbp".into())),
870                        ("value".into(), Expression::Num(100.into()))
871                    ]))
872                )))
873            ))
874        )
875    }
876
877    #[test]
878    fn wtf() {
879        let input = r#"false ? true"#;
880        assert_eq!(
881            expression.parse_peek(input),
882            Ok(("? true", Expression::Boolean(false)))
883        )
884    }
885}