#![allow(dead_code)] //TODO eventually turn this off mod bnf; mod choice; mod combinators; mod parser; mod primitives; mod sequence; pub use parser::{ParseResult, Parser, ParserInput}; #[cfg(test)] mod tests { use super::*; use crate::choice::choice; use crate::combinators::repeated; use crate::primitives::{any_char, literal, literal_char, one_of, pred}; use crate::sequence::seq; use std::collections::HashMap; #[test] fn test_parsing() { let output = literal("a")("a yolo"); assert_eq!(output.unwrap(), ("a", " yolo")); } /* * JSON BNF * ::= ::= | | | | | ::= "[" [] {"," }* "]" ::= "{" [] {"," }* "}" ::= ":" */ #[derive(Debug, Clone, PartialEq)] enum JsonValue { Null, Bool(bool), Str(String), Num(f64), Array(Vec), Object(HashMap), } 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> {} fn json_null<'a>() -> impl JsonParser<'a, JsonValue> { literal("null").to(JsonValue::Null) } fn json_bool<'a>() -> impl JsonParser<'a, JsonValue> { choice(( literal("true").to(JsonValue::Bool(true)), literal("false").to(JsonValue::Bool(false)), )) } fn json_number() -> impl JsonParser<'static, JsonValue> { let digit = || one_of("1234567890"); let digits = || 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) }) } fn json_string() -> impl JsonParser<'static, JsonValue> { seq(( literal_char('"'), repeated(pred(any_char, |ch| *ch != '"')), literal_char('"'), )) .map(|(_, s, _)| JsonValue::Str(s.iter().cloned().collect::())) } fn whitespace() -> impl JsonParser<'static, ()> { repeated(literal_char(' ')).to(()) } fn json_array() -> impl JsonParser<'static, 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) } } //fn json_object() -> impl JsonParser<'static, JsonValue> {} fn json_value() -> impl JsonParser<'static, JsonValue> { choice(( json_null(), json_bool(), json_number(), json_string(), json_array(), )) } #[test] fn parse_json_primitives() { assert_eq!( json_string().parse(r#""yolo swagg""#).unwrap(), (JsonValue::Str("yolo swagg".into()), "") ); assert_eq!( json_number().parse("-383").unwrap().0, JsonValue::Num(-383f64) ); assert_eq!( json_number().parse("-.383").unwrap().0, JsonValue::Num(-0.383) ); assert_eq!( json_number().parse(".383").unwrap().0, JsonValue::Num(0.383) ); assert_eq!( json_number().parse("-1.383").unwrap().0, JsonValue::Num(-1.383) ); } #[test] fn parse_json_array() { assert!(json_array().parse(r#"[ 4, 9, "ara",]"#).is_err()); assert_eq!( json_array().parse("[[],[]]").unwrap().0, JsonValue::Array(vec![JsonValue::Array(vec![]), JsonValue::Array(vec![])]) ); assert_eq!( json_array().parse(r#"[ 4, 9, "foo" ]"#).unwrap(), ( JsonValue::Array(vec![ JsonValue::Num(4.), JsonValue::Num(9.0), JsonValue::Str("foo".to_string()) ]), "" ) ); assert_eq!( json_array().parse(r#"[8,null,[],5]"#).unwrap(), ( JsonValue::Array(vec![ JsonValue::Num(8.), JsonValue::Null, JsonValue::Array(vec![]), JsonValue::Num(5.) ]), "" ) ); assert_eq!(json_value().parse("true"), Ok((JsonValue::Bool(true), ""))); } }