#![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}; #[cfg(test)] mod tests { use super::*; use crate::choice::choice; use crate::combinators::{one_or_more, zero_or_more}; 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), } #[test] fn parse_json() { let json_null = literal("null").to(JsonValue::Null); let json_bool = choice(( literal("true").to(JsonValue::Bool(true)), literal("false").to(JsonValue::Bool(false)), )); let digit = || one_of("1234567890"); assert_eq!(digit().parse("3"), Ok(("3", ""))); let json_number_inner = choice(( seq(( one_or_more(digit()), literal(".").then(zero_or_more(digit())).optional(), )) .map(|(mut digits, maybe_more)| { if let Some((point, more)) = maybe_more { digits.push(point); digits.extend(more.into_iter()); } digits.into_iter().collect::() }), seq((literal("."), one_or_more(digit()))).map(|(_point, digits)| { let mut d = vec!["."]; d.extend(digits.into_iter()); d.into_iter().collect::() }), )) .map(|digits| digits.parse::().unwrap()); let json_number = literal("-") .optional() .then(json_number_inner) .map(|(maybe_sign, mut val)| { if maybe_sign.is_some() { val *= -1.0; } JsonValue::Num(val) }); 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) ); let json_string = seq(( literal_char('"'), pred(any_char, |ch| *ch != '"'), literal_char('"'), )) .map(|(_, s, _)| JsonValue::Str(s.to_string())); let json_value = choice((json_null, json_bool, json_number, json_string)); assert_eq!(json_value.parse("true"), Ok((JsonValue::Bool(true), ""))); } }