# parser_fuck ![GitHub](https://img.shields.io/github/license/MeowType/parser_fuck?color=brightgreen) ![Rust](https://github.com/MeowType/parser_fuck/workflows/Rust/badge.svg) ![Crates.io](https://img.shields.io/crates/v/parser_fuck) A simple parser combinator library ## example ```rust use parser_fuck::*; use std::collections::HashMap; use std::f64; use std::ops::Range; static CODE: &'static str = "{ \"a\": 1, \"b\": true, \"c\": [null, 1.5, false], \"d\": { \"v\": \"asd\" } }"; fn main() { let r = json(CODE); println!("{:?}", r); assert_eq!( r, Ok(JsonVal::Object({ let mut map = HashMap::new(); map.insert("a".to_string(), JsonVal::Number(1.0)); map.insert("b".to_string(), JsonVal::Bool(true)); map.insert( "c".to_string(), JsonVal::Array(vec![ JsonVal::Null, JsonVal::Number(1.5), JsonVal::Bool(false), ]), ); map.insert( "d".to_string(), JsonVal::Object({ let mut map = HashMap::new(); map.insert("v".to_string(), JsonVal::String("asd".to_string())); map }), ); map })) ) } pub fn json(code: &str) -> JsonResult { let code = code.span(); value.parse(code).unwrap() } fn boolval(input: CharSpan) -> Option { substr("true") .map(|_| JsonVal::Bool(true)) .or(substr("false").map(|_| JsonVal::Bool(false))) .parse(input) } fn nullval(input: CharSpan) -> Option { substr("null").map(|_| JsonVal::Null).parse(input) } fn numberval(input: CharSpan) -> Option { fn num_start(input: CharSpan) -> Option> { satisfy(|c: Char| { c.char(|c: char, _| c != '0' && c.is_ascii_digit()) .unwrap_or(false) }) .parse(input) } fn num_body(input: CharSpan) -> Option> { satisfy(|c: Char| c.char(|c: char, _| c.is_ascii_digit()).unwrap_or(false)).parse(input) } one('-') .may() .and( one('0').or(num_start .many1() .and(num_body.many()) .map(range_of_many1_many)), ) .map(range_of_optrange_range) .and( one('.') .and(num_body.many1()) .map(range_of_range_many1) .may(), ) .map(range_of_range_optrange) .and( one('e') .or(one('E')) .and(one('-').or(one('+')).may()) .map(range_of_range_optrange) .and(num_body.many1()) .map(range_of_range_many1) .may(), ) .map(range_of_range_optrange) .map(|v: Range| { let s: String = input.com_string(v).unwrap(); let v: f64 = s.parse::().unwrap(); JsonVal::Number(v) }) .parse(input.ref_clone()) } fn stringval(input: CharSpan) -> Option { fn str_esc(input: CharSpan) -> Option> { one('\\') .and({ one('"') .map(|_| '"') .or(one('\\').map(|_| '\\')) .or(one('/').map(|_| '/')) .or(one('b').map(|_| '')) .or(one('f').map(|_| ' ')) .or(one('n').map(|_| '\n')) .or(one('r').map(|_| '\r')) .or(one('t').map(|_| '\t')) .or(one('u') .and( satisfy(|c: Char| c.char(|c: char, _| c.is_digit(16)).unwrap_or(false)) .some(4), ) .map(|(_, u)| { let s = input.com_string(range_of_many1(u)).unwrap(); let hex: u32 = u32::from_str_radix(&*s, 16).unwrap(); let c = std::char::from_u32(hex).unwrap(); c })) .map(|v| Result::::Ok(v)) .or_trans(|i: CharSpan, ep| { let loc = i.loc_range(ep).unwrap(); Err(JsonParserError { loc, msg: "Illegal escape character".to_string(), }) }) }) .map(|(_, v)| v) .parse(input.ref_clone()) } fn str_body(input: CharSpan) -> Option> { satisfy(|c: Char| c == '' || c == ' ' || c == '\n' || c == '\r' || c == '\t') .map(|i| { let loc = input.loc_range(i).unwrap(); Err(JsonParserError { loc, msg: "Control characters are not allowed in the string".to_string(), }) }) .or(str_esc) .or(satisfy(|c: Char| c != '"').map(|i| { let s = input.com_string(i).unwrap(); let c = s.chars().next().unwrap(); Ok(c) })) .parse(input.ref_clone()) } one('"') .and(str_body.many()) .and(one('"')) .map( |((_, v), _): ( (Range, Vec>), Range, )| { let mut val = String::new(); for c in v { let c = c?; val.push(c); } let jv = JsonVal::String(val); Ok(jv) }, ) .parse(input.ref_clone()) } fn whitespace(input: CharSpan) -> Option<()> { satisfy(|c: Char| c.is_wrap() || c == ' ' || c == '\t') .many() .map(|_| {}) .parse(input) } fn value(input: CharSpan) -> Option { whitespace .and( stringval .or(object) .or(array) .or(numberval.or(boolval).or(nullval).map(|v| Ok(v))), ) .and(whitespace) .map(|((_, v), _)| v) .or_trans(|i: CharSpan, ep| { let loc = i.loc_range(ep).unwrap(); Err(JsonParserError { loc, msg: "Invaild character".to_string(), }) }) .parse(input) } fn array(input: CharSpan) -> Option { one('[') .and({ value .and(one(',').and(value).many()) .map(|(f, v)| { let mut vals: Vec = vec![f?]; for vv in v { let (_, val) = vv; vals.push(val?); } Ok(vals) }) .or(whitespace.map(|_| Ok(vec![]))) }) .and(one(']').map(|_| Ok(())).or_trans(|i: CharSpan, ep| { let loc = i.loc_range(ep); let loc = loc.unwrap(); Err(JsonParserError { loc, msg: "Need \"]\" but not found it".to_string(), }) })) .map( |((_, v), e): ((_, JsonResults>), JsonResults<()>)| { e?; let v = v?; Ok(JsonVal::Array(v)) }, ) .parse(input) } fn object(input: CharSpan) -> Option { fn kv(input: CharSpan) -> Option> { whitespace .and(stringval) .and(whitespace) .and(one(':').map(|v| Ok(v)).or_trans(|i: CharSpan, ep| { let loc = i.loc_range(ep).unwrap(); Err(JsonParserError { loc, msg: "Need \":\" but not found it".to_string(), }) })) .and(value) .map(|((((_, k), _), col), v)| { let k = k?; let _ = col?; let v = v?; let key = if let JsonVal::String(key) = k { key } else { panic!("never") }; Ok((key, v)) }) .parse(input) } one('{') .and({ kv.and({ one(',').and(kv).many() }) .map(|(f, vs)| { let mut vals: HashMap = HashMap::new(); let (k, v) = f?; vals.insert(k, v); for vv in vs { let (_, val) = vv; let (k, v) = val?; vals.insert(k, v); } Ok(vals) }) .or(whitespace.map(|_| Ok(HashMap::new()))) }) .and(one('}').map(|_| Ok(())).or_trans(|i: CharSpan, ep| { let loc = i.loc_range(ep).unwrap(); Err(JsonParserError { loc, msg: "Need \"}\" but not found it".to_string(), }) })) .map( |((_, v), e): ((_, JsonResults>), JsonResults<()>)| { e?; let v = v?; Ok(JsonVal::Object(v)) }, ) .parse(input) } #[derive(Debug, Clone, PartialEq, Eq)] pub struct JsonParserError { pub loc: LocRange, pub msg: String, } pub type JsonResults = Result; pub type JsonResult = Result; #[derive(Debug, Clone, PartialEq)] pub enum JsonVal { String(String), Number(f64), Object(HashMap), Array(Vec), Bool(bool), Null, } ```