yojson_rs/
parser.rs

1//! Definition of a parse fucntion.
2
3use crate::pest::Parser;
4use pest::iterators::Pair;
5use std::collections::HashMap;
6
7use super::value;
8
9#[allow(clippy::upper_case_acronyms)]
10#[derive(Parser)]
11#[grammar = "parser.pest"]
12struct YojsonParser;
13
14pub fn parse(text: &str) -> Result<value::Value, pest::error::Error<Rule>> {
15  let json = YojsonParser::parse(Rule::json, text)?.next().unwrap();
16  let value = parse_value(json);
17  Ok(value)
18}
19
20fn parse_value(pair: Pair<Rule>) -> value::Value {
21  match pair.as_rule() {
22    Rule::null => value::Value::Null,
23    Rule::bool => value::Value::Bool(pair.as_str().parse().unwrap()),
24    Rule::integer => value::Value::Integer(pair.as_str().parse().unwrap()),
25    Rule::float => {
26      let str = pair.as_str();
27      let f = if str == "NaN" {
28        f64::NAN
29      } else if str == "Infinity" {
30        f64::INFINITY
31      } else if str == "-Infinity" {
32        f64::NEG_INFINITY
33      } else {
34        str.parse().unwrap()
35      };
36      value::Value::Float(f)
37    }
38    Rule::string => {
39      let str = parse_string(pair.into_inner().next().unwrap());
40      value::Value::String(str)
41    }
42    Rule::assoc => {
43      let mut assoc = HashMap::new();
44      pair.into_inner().for_each(|pair| {
45        let mut inner_rules = pair.into_inner();
46        let name = parse_name(inner_rules.next().unwrap());
47        let value = parse_value(inner_rules.next().unwrap());
48        assoc.insert(name, value);
49      });
50      value::Value::Assoc(assoc)
51    }
52    Rule::array => value::Value::Array(pair.into_inner().map(parse_value).collect()),
53    Rule::tuple => value::Value::Tuple(pair.into_inner().map(parse_value).collect()),
54    Rule::variant => {
55      let mut inner_rules = pair.into_inner();
56      let name = parse_name(inner_rules.next().unwrap());
57      let value = match inner_rules.next() {
58        None => None,
59        Some(rule) => Some(Box::new(parse_value(rule))),
60      };
61      let variant = (name, value);
62      value::Value::Variant(variant)
63    }
64    Rule::json
65    | Rule::EOI
66    | Rule::pair
67    | Rule::value
68    | Rule::inner
69    | Rule::name
70    | Rule::ascii_inner
71    | Rule::quoted_string
72    | Rule::c
73    | Rule::escape_char
74    | Rule::unicode_char
75    | Rule::unquoted_string
76    | Rule::ascii_char
77    | Rule::WHITESPACE
78    | Rule::COMMENT => unreachable!(),
79  }
80}
81
82fn parse_name(pair: Pair<Rule>) -> String {
83  let mut inner_rules = pair.into_inner().peekable();
84  let str = match inner_rules.peek().unwrap().as_rule() {
85    Rule::ascii_inner => inner_rules.next().unwrap().as_str().to_string(),
86    Rule::inner => {
87      let mut s = String::new();
88      for pair in inner_rules.next().unwrap().into_inner() {
89        match pair.as_rule() {
90          Rule::c => s.push_str(pair.as_str()),
91          Rule::escape_char => {
92            let c = match pair.as_str().chars().nth(1).unwrap() {
93              '"' => '\"',
94              '\\' => '\\',
95              '/' => '/',
96              'b' => '\u{0008}', // Backspace
97              'f' => '\u{000c}', // Form Feed
98              'n' => '\n',
99              'r' => '\r',
100              't' => '\t',
101              _ => unreachable!(),
102            };
103            s.push(c)
104          }
105          Rule::unicode_char => {
106            let hex = pair.as_str().chars().skip(2).collect::<String>();
107            let hex_i64 = i64::from_str_radix(&hex, 16).unwrap();
108            let str = String::from_utf8(vec![hex_i64 as u8]).unwrap();
109            s.push_str(&str)
110          }
111          _ => break,
112        }
113      }
114      s
115    }
116    _ => unreachable!(),
117  };
118  str
119}
120
121fn parse_string(pair: Pair<Rule>) -> String {
122  let mut s = String::new();
123  let inner_rules = pair.into_inner();
124  for pair in inner_rules {
125    match pair.as_rule() {
126      Rule::c => s.push_str(pair.as_str()),
127      Rule::escape_char => {
128        let c = match pair.as_str().chars().nth(1).unwrap() {
129          '"' => '\"',
130          '\\' => '\\',
131          '/' => '/',
132          'b' => '\u{0008}', // Backspace
133          'f' => '\u{000c}', // Form Feed
134          'n' => '\n',
135          'r' => '\r',
136          't' => '\t',
137          _ => unreachable!(),
138        };
139        s.push(c)
140      }
141      Rule::unicode_char => {
142        let hex = pair.as_str().chars().skip(2).collect::<String>();
143        let hex_i64 = i64::from_str_radix(&hex, 16).unwrap();
144        let str = String::from_utf8(vec![hex_i64 as u8]).unwrap();
145        s.push_str(&str)
146      }
147      _ => break,
148    }
149  }
150  s
151}