lite_json/
json_parser.rs

1#[cfg(not(feature = "std"))]
2extern crate alloc;
3
4#[cfg(not(feature = "std"))]
5use alloc::vec::Vec;
6
7use crate::json::{JsonObject, JsonValue, NumberValue};
8use lite_parser::{
9    impls::SimpleError,
10    literals,
11    parser::{
12        Concat, Concat3, Either, OneOf, OneOrMore, Parser, ParserContext, ParserOptions,
13        ZeroOrMore, ZeroOrOne,
14    },
15    parsers,
16    traits::{Error, Input, ResultOf},
17};
18
19use core::convert::TryInto;
20
21literals! {
22    pub WhitespaceChar => '\u{0020}' | '\u{000D}' | '\u{000A}' | '\u{0009}';
23    pub SignChar => '+' | '-';
24    pub NegativeSignChar => '-';
25    pub EChar => 'E' | 'e';
26    pub OneToNineChar => '1' ..= '9';
27    pub DigitChar => '0' ..= '9';
28    pub DotChar => '.';
29    pub HexChar => '0' ..= '9' | 'a' ..= 'f' | 'A' ..= 'F';
30    pub DoubleQuoteChar => '"';
31    pub OpenCurlyBracketChar => '{';
32    pub CloseCurlyBracketChar => '}';
33    pub CommaChar => ',';
34    pub OpenSquareBracketChar => '[';
35    pub CloseSquareBracketChar => ']';
36}
37
38pub type Whitespace = ZeroOrMore<WhitespaceChar>;
39
40pub type Sign = ZeroOrOne<SignChar>;
41
42pub type Digits = OneOrMore<DigitChar>;
43
44parsers! {
45    pub PositiveInteger = OneOf<Concat<OneToNineChar, Digits>, DigitChar>, u64, (output) => {
46        match output {
47            Either::A((c, cs)) => {
48                let mut val = c.to_digit(10).unwrap() as u64;
49                for c in cs {
50                    val *= 10;
51                    val += c.to_digit(10).unwrap() as u64;
52                }
53                val
54            },
55            Either::B(c) => c.to_digit(10).unwrap() as u64,
56        }
57    };
58
59    pub NegativeInteger = Concat<NegativeSignChar, PositiveInteger>, u64, (output) => {
60        let (_, output) = output;
61        output
62    };
63
64    pub Integer = OneOf<PositiveInteger, NegativeInteger>, (bool, u64), (output) => {
65        match output {
66            Either::A(a) => (false, a),
67            Either::B(b) => (true, b),
68        }
69    };
70
71    pub Fraction = ZeroOrOne<Concat<DotChar, Digits>>, (u64, u32), (output) => {
72        match output {
73            Either::A((_, cs)) => {
74                let mut val = 0u64;
75                let len = cs.len();
76                for c in cs {
77                    val *= 10u64;
78                    val += c.to_digit(10).unwrap() as u64;
79                }
80                (val, len as u32)
81            },
82            Either::B(_) => (0u64, 0u32),
83        }
84    };
85
86    pub Exponent = ZeroOrOne<Concat3<EChar, Sign, Digits>>, i32, (output) => {
87        match output {
88            Either::A((_, (s, cs))) => {
89                let mul = if let Either::A('-') = s { -1 } else { 1 };
90                let mut val = 0i32;
91                for c in cs {
92                    val *= 10;
93                    val += c.to_digit(10).unwrap() as i32;
94                }
95                val * mul
96            },
97            Either::B(_) => 0,
98        }
99    };
100
101    pub Number = Concat3<Integer, Fraction, Exponent>, NumberValue, (output) => {
102        let ((s, n), (f, e)) = output;
103        NumberValue {
104            integer: n,
105            fraction: f.0,
106            fraction_length: f.1,
107            exponent: e,
108            negative: s,
109        }
110    };
111
112    pub Hex = HexChar, u8, (output) => {
113        output.to_digit(16).unwrap() as u8
114    };
115
116    pub String = Concat3<DoubleQuoteChar, Characters, DoubleQuoteChar>, Vec<char>, (output) => {
117        match (output.1).0 {
118            Either::A(bytes) => bytes,
119            Either::B(_) => Vec::new(),
120        }
121    };
122}
123
124pub struct Escape;
125
126impl<I: Input> Parser<I> for Escape {
127    type Output = char;
128    fn parse(
129        input: &I,
130        current: I::Position,
131        context: &ParserContext,
132    ) -> ResultOf<I, Self::Output> {
133        let (c, next) = input
134            .next(current)
135            .map_err(|e| e.add_reason(current, "Escape"))?;
136        match c {
137            '"' | '\\' | '/' | 'b' | 'f' | 'n' | 'r' | 't' => Ok((c, next)),
138            'u' => {
139                let (b1, next) = <Hex as Parser<I>>::parse(input, next, context)?;
140                let (b2, next) = <Hex as Parser<I>>::parse(input, next, context)?;
141                let (b3, next) = <Hex as Parser<I>>::parse(input, next, context)?;
142                let (b4, next) = <Hex as Parser<I>>::parse(input, next, context)?;
143                let byte = (b1 as u32) << 24 | (b2 as u32) << 16 | (b3 as u32) << 8 | (b4 as u32);
144                let c = byte
145                    .try_into()
146                    .map_err(|_| input.error_at(current, "Escape"))?;
147                Ok((c, next))
148            }
149            _ => Err(input.error_at(current, "Escape")),
150        }
151    }
152}
153
154pub struct Character;
155
156impl<I: Input> Parser<I> for Character {
157    type Output = char;
158    fn parse(
159        input: &I,
160        current: I::Position,
161        context: &ParserContext,
162    ) -> ResultOf<I, Self::Output> {
163        let (c, next) = input
164            .next(current)
165            .map_err(|e| e.add_reason(current, "Character"))?;
166        match c {
167            '\\' => <Escape as Parser<I>>::parse(input, next, context),
168            '"' => Err(input.error_at(current, "Character")),
169            _ => Ok((c, next)),
170        }
171    }
172}
173
174pub type Characters = ZeroOrMore<Character>;
175
176pub struct Member;
177
178impl<I: Input> Parser<I> for Member {
179    type Output = (Vec<char>, JsonValue);
180    fn parse(
181        input: &I,
182        current: I::Position,
183        context: &ParserContext,
184    ) -> ResultOf<I, Self::Output> {
185        let (_, next) = <Whitespace as Parser<I>>::parse(input, current, context)?;
186        let (key, next) = <String as Parser<I>>::parse(input, next, context)?;
187        let (_, next) = <Whitespace as Parser<I>>::parse(input, next, context)?;
188        let next = input
189            .next(next)
190            .and_then(|(c, next)| {
191                if c == ':' {
192                    Ok(next)
193                } else {
194                    Err(input.error_at(next, "Character"))
195                }
196            })
197            .map_err(|e| e.add_reason(current, "Member"))?;
198        let (value, next) = <Element as Parser<I>>::parse(input, next, context)?;
199        Ok(((key, value), next))
200    }
201}
202
203pub struct Element;
204
205impl<I: Input> Parser<I> for Element {
206    type Output = JsonValue;
207    fn parse(
208        input: &I,
209        current: I::Position,
210        context: &ParserContext,
211    ) -> ResultOf<I, Self::Output> {
212        let (_, next) = <Whitespace as Parser<I>>::parse(input, current, context)?;
213        let (output, next) = <Value as Parser<I>>::parse(input, next, context)?;
214        let (_, next) = <Whitespace as Parser<I>>::parse(input, next, context)?;
215        Ok((output, next))
216    }
217}
218
219pub struct Value;
220
221impl<I: Input> Parser<I> for Value
222where
223    I::Position: Copy,
224{
225    type Output = JsonValue;
226    fn parse(
227        input: &I,
228        current: I::Position,
229        context: &ParserContext,
230    ) -> ResultOf<I, Self::Output> {
231        if let Ok((output, next)) = <Object as Parser<I>>::parse(input, current, context) {
232            return Ok((JsonValue::Object(output), next));
233        }
234        if let Ok((output, next)) = <Array as Parser<I>>::parse(input, current, context) {
235            return Ok((JsonValue::Array(output), next));
236        }
237        if let Ok((output, next)) = <String as Parser<I>>::parse(input, current, context) {
238            return Ok((JsonValue::String(output), next));
239        }
240        if let Ok((output, next)) = <Number as Parser<I>>::parse(input, current, context) {
241            return Ok((JsonValue::Number(output), next));
242        }
243        let (value, next) = input.next_range(current, 4)?;
244        if value == "null" {
245            return Ok((JsonValue::Null, next));
246        }
247        if value == "true" {
248            return Ok((JsonValue::Boolean(true), next));
249        }
250        let (value, next) = input.next_range(current, 5)?;
251        if value == "false" {
252            return Ok((JsonValue::Boolean(false), next));
253        }
254        Err(input.error_at(current, "Value"))
255    }
256}
257
258pub struct Object;
259
260impl<I: Input> Parser<I> for Object {
261    type Output = JsonObject;
262    fn parse(
263        input: &I,
264        current: I::Position,
265        context: &ParserContext,
266    ) -> ResultOf<I, Self::Output> {
267        let context = &context.nest(input, current)?;
268        let (_, next) = <OpenCurlyBracketChar as Parser<I>>::parse(input, current, context)?;
269        let (output, next) =
270            <OneOf<Members, Whitespace> as Parser<I>>::parse(input, next, context)?;
271        let (_, next) = <CloseCurlyBracketChar as Parser<I>>::parse(input, next, context)?;
272        let output = match output {
273            Either::A(a) => a,
274            Either::B(_) => Vec::new(),
275        };
276        Ok((output, next))
277    }
278}
279
280pub struct Members;
281
282impl<I: Input> Parser<I> for Members {
283    type Output = Vec<(Vec<char>, JsonValue)>;
284    fn parse(
285        input: &I,
286        current: I::Position,
287        context: &ParserContext,
288    ) -> ResultOf<I, Self::Output> {
289        let (output, next) = <Member as Parser<I>>::parse(input, current, context)?;
290        let (rest, next) =
291            <ZeroOrMore<Concat<CommaChar, Member>> as Parser<I>>::parse(input, next, context)?;
292        let mut result = Vec::new();
293        result.push(output);
294        if let Either::A(rest) = rest {
295            result.extend(rest.into_iter().map(|(_, m)| m))
296        }
297        Ok((result, next))
298    }
299}
300
301pub struct Elements;
302
303impl<I: Input> Parser<I> for Elements {
304    type Output = Vec<JsonValue>;
305    fn parse(
306        input: &I,
307        current: I::Position,
308        context: &ParserContext,
309    ) -> ResultOf<I, Self::Output> {
310        let (output, next) = <Element as Parser<I>>::parse(input, current, context)?;
311        let (rest, next) =
312            <ZeroOrMore<Concat<CommaChar, Element>> as Parser<I>>::parse(input, next, context)?;
313        let mut result = Vec::new();
314        result.push(output);
315        if let Either::A(rest) = rest {
316            result.extend(rest.into_iter().map(|(_, m)| m))
317        }
318        Ok((result, next))
319    }
320}
321
322pub struct Array;
323
324impl<I: Input> Parser<I> for Array {
325    type Output = Vec<JsonValue>;
326    fn parse(
327        input: &I,
328        current: I::Position,
329        context: &ParserContext,
330    ) -> ResultOf<I, Self::Output> {
331        let context = &context.nest(input, current)?;
332        let (_, next) = <OpenSquareBracketChar as Parser<I>>::parse(input, current, context)?;
333        let (output, next) =
334            <OneOf<Elements, Whitespace> as Parser<I>>::parse(input, next, context)?;
335        let (_, next) = <CloseSquareBracketChar as Parser<I>>::parse(input, next, context)?;
336        let output = match output {
337            Either::A(a) => a,
338            Either::B(_) => Vec::new(),
339        };
340        Ok((output, next))
341    }
342}
343
344pub struct Json;
345
346impl<I: Input> Parser<I> for Json {
347    type Output = <Element as Parser<I>>::Output;
348    fn parse(
349        input: &I,
350        current: I::Position,
351        context: &ParserContext,
352    ) -> ResultOf<I, Self::Output> {
353        let (_, next) = <Whitespace as Parser<I>>::parse(input, current, context)?;
354        let (res, next) = <Element as Parser<I>>::parse(input, next, context)?;
355        let (_, next) = <Whitespace as Parser<I>>::parse(input, next, context)?;
356        if input.is_end(next) {
357            Ok((res, next))
358        } else {
359            Err(input.error_at(next, "Expect end of input"))
360        }
361    }
362}
363
364pub fn parse_json(input: &str) -> Result<JsonValue, SimpleError> {
365    parse_json_with_options(input, Default::default())
366}
367
368pub fn parse_json_with_options(
369    input: &str,
370    options: ParserOptions,
371) -> Result<JsonValue, SimpleError> {
372    Json::parse(&input, Default::default(), &ParserContext::new(options)).map(|(ret, _)| ret)
373}
374
375#[cfg(test)]
376mod tests {
377    use super::*;
378    use crate::NumberValue;
379    use lite_parser::impls::SimplePosition;
380
381    #[test]
382    fn it_works() {
383        assert_eq!(
384            parse_json(
385                &r#"{ "test": 1, "test2": [1e-4, 2.041e2, true, false, null, "\"1\n\""], "test3": [], "test4": {} }"#
386            ),
387            Ok(JsonValue::Object(vec![
388                (
389                    vec!['t', 'e', 's', 't'],
390                    JsonValue::Number(NumberValue {
391                        integer: 1,
392                        fraction: 0,
393                        fraction_length: 0,
394                        exponent: 0,
395                        negative: false,
396                    })
397                ),
398                (
399                    vec!['t', 'e', 's', 't', '2'],
400                    JsonValue::Array(vec![
401                        JsonValue::Number(NumberValue {
402                            integer: 1,
403                            fraction: 0,
404                            fraction_length: 0,
405                            exponent: -4,
406                            negative: false,
407                        }),
408                        JsonValue::Number(NumberValue {
409                            integer: 2,
410                            fraction: 41,
411                            fraction_length: 3,
412                            exponent: 2,
413                            negative: false,
414                        }),
415                        JsonValue::Boolean(true),
416                        JsonValue::Boolean(false),
417                        JsonValue::Null,
418                        JsonValue::String(vec!['\"', '1', 'n', '\"'])
419                    ])
420                ),
421                (vec!['t', 'e', 's', 't', '3'], JsonValue::Array(vec![])),
422                (vec!['t', 'e', 's', 't', '4'], JsonValue::Object(vec![]))
423            ]))
424        )
425    }
426
427    #[test]
428    fn it_should_consume_all() {
429        assert_eq!(
430            parse_json(&r#""1"a"#),
431            Err(SimpleError {
432                reasons: vec![(
433                    SimplePosition {
434                        index: 3,
435                        line: 0,
436                        column: 3
437                    },
438                    "Expect end of input"
439                )]
440            })
441        )
442    }
443
444    #[test]
445    fn it_accepts_nest_level() {
446        assert_eq!(
447            parse_json_with_options(
448                &r#"{ "test": 1 }"#,
449                ParserOptions {
450                    max_nest_level: Some(1)
451                }
452            ),
453            Ok(JsonValue::Object(vec![(
454                vec!['t', 'e', 's', 't'],
455                JsonValue::Number(NumberValue {
456                    integer: 1,
457                    fraction: 0,
458                    fraction_length: 0,
459                    exponent: 0,
460                    negative: false,
461                })
462            ),]))
463        );
464    }
465
466    #[test]
467    fn it_accepts_more_nest_level() {
468        assert_eq!(
469            parse_json_with_options(
470                &r#"{ "test": { "a": [ {} ] } }"#,
471                ParserOptions {
472                    max_nest_level: Some(5)
473                }
474            ),
475            Ok(JsonValue::Object(vec![(
476                vec!['t', 'e', 's', 't'],
477                JsonValue::Object(vec![(
478                    vec!['a'],
479                    JsonValue::Array(vec![JsonValue::Object(vec![])])
480                )])
481            )]))
482        );
483    }
484
485    #[test]
486    fn it_error_on_too_deep_nest() {
487        assert_eq!(
488            parse_json_with_options(
489                &r#"{ "test": { "a": [ {} ] } }"#,
490                ParserOptions {
491                    max_nest_level: Some(3)
492                }
493            ),
494            Err(SimpleError {
495                reasons: vec![(
496                    SimplePosition {
497                        index: 0,
498                        line: 0,
499                        column: 0
500                    },
501                    "Value"
502                )]
503            })
504        );
505    }
506
507    #[test]
508    fn handles_decimal_number() {
509        assert_eq!(
510            parse_json(&r#"-1.5"#,),
511            Ok(JsonValue::Number(NumberValue {
512                integer: 1,
513                fraction: 5,
514                fraction_length: 1,
515                exponent: 0,
516                negative: true,
517            }))
518        );
519
520        assert_eq!(
521            parse_json(&r#"-0.5"#,),
522            Ok(JsonValue::Number(NumberValue {
523                integer: 0,
524                fraction: 5,
525                fraction_length: 1,
526                exponent: 0,
527                negative: true,
528            }))
529        );
530
531        assert_eq!(
532            parse_json(&r#"0.5"#,),
533            Ok(JsonValue::Number(NumberValue {
534                integer: 0,
535                fraction: 5,
536                fraction_length: 1,
537                exponent: 0,
538                negative: false,
539            }))
540        );
541    }
542}