use crate::choice::choice; use crate::combinators::repeated; use crate::primitives::{any_char, literal, literal_char, one_of, pred}; use crate::sequence::seq; use crate::Parser; /* * JSON BNF * ::= ::= | | | | | ::= "[" [] {"," }* "]" ::= "{" [] {"," }* "}" ::= ":" */ #[derive(Debug, Clone, PartialEq)] pub enum JsonValue { Null, Bool(bool), Str(String), Num(f64), Array(Vec), Object(Vec<(String, JsonValue)>), } pub trait JsonParser<'a, T>: Parser<&'a str, T, &'a str> {} impl<'a, T, P> JsonParser<'a, T> for P where P: Parser<&'a str, T, &'a str> {} pub fn json_null<'a>() -> impl JsonParser<'a, JsonValue> { literal("null").to(JsonValue::Null) } pub fn json_bool<'a>() -> impl JsonParser<'a, JsonValue> { choice(( literal("true").to(JsonValue::Bool(true)), literal("false").to(JsonValue::Bool(false)), )) } pub fn json_number<'a>() -> impl JsonParser<'a, JsonValue> { fn digit<'a>() -> impl JsonParser<'a, &'a str> { one_of("1234567890") } fn digits<'a>() -> impl JsonParser<'a, Vec<&'a str>> { repeated(digit()).at_least(1) } let json_number_inner = choice(( seq((digits(), literal(".").ignore_then(digits()).optional())).map( |(mut digits, maybe_decimal)| { if let Some(decimal_digits) = maybe_decimal { digits.push("."); digits.extend(decimal_digits.into_iter()); } digits.into_iter().collect::() }, ), literal(".").ignore_then(digits()).map(|decimal_digits| { let mut d = vec!["."]; d.extend(decimal_digits.into_iter()); d.into_iter().collect::() }), )) .map(|digits| digits.parse::().unwrap()); literal("-") .optional() .then(json_number_inner) .map(|(maybe_sign, mut val)| { if maybe_sign.is_some() { val *= -1.0; } JsonValue::Num(val) }) } pub fn json_string_raw<'a>() -> impl JsonParser<'a, String> { seq(( literal_char('"'), repeated(pred(any_char, |ch| *ch != '"')), literal_char('"'), )) .map(|(_, s, _)| s.iter().cloned().collect::()) } pub fn json_string<'a>() -> impl JsonParser<'a, JsonValue> { json_string_raw().map(JsonValue::Str) } fn whitespace<'a>() -> impl JsonParser<'a, ()> { repeated(choice(( literal_char('\t'), literal_char('\n'), literal_char(' '), ))) .to(()) } pub fn json_array<'a>() -> impl JsonParser<'a, JsonValue> { move |input| { let val = json_value().surrounded_by(whitespace()); repeated(val) .separated_by(literal(","), false) .delimited(literal_char('['), literal_char(']')) .map(JsonValue::Array) .parse(input) } } pub fn json_object<'a>() -> impl JsonParser<'a, JsonValue> { move |input| { let kv = json_string_raw() .surrounded_by(whitespace()) .then_ignore(literal_char(':')) .then(json_value().surrounded_by(whitespace())); repeated(kv) .separated_by(literal_char(','), false) .delimited(literal_char('{'), literal_char('}')) .map(JsonValue::Object) .parse(input) } } pub fn json_value<'a>() -> impl JsonParser<'a, JsonValue> { choice(( json_null(), json_bool(), json_number(), json_string(), json_array(), json_object(), )) }