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); asserteq!( r, Ok(JsonVal::Object({ let mut map = HashMap::new(); map.insert("a".tostring(), JsonVal::Number(1.0)); map.insert("b".tostring(), JsonVal::Bool(true)); map.insert( "c".tostring(), JsonVal::Array(vec![ JsonVal::Null, JsonVal::Number(1.5), JsonVal::Bool(false), ]), ); map.insert( "d".tostring(), JsonVal::Object({ let mut map = HashMap::new(); map.insert("v".tostring(), 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 numstart(input: CharSpan) -> Option> { satisfy(|c: Char| { c.char(|c: char, _| c != '0' && c.isasciidigit()) .unwrapor(false) }) .parse(input) } fn numbody(input: CharSpan) -> Option> { satisfy(|c: Char| c.char(|c: char, _| c.isasciidigit()).unwrapor(false)).parse(input) } one('-') .may() .and( one('0').or(numstart .many1() .and(numbody.many()) .map(rangeofmany1many)), ) .map(rangeofoptrangerange) .and( one('.') .and(numbody.many1()) .map(rangeofrangemany1) .may(), ) .map(rangeofrangeoptrange) .and( one('e') .or(one('E')) .and(one('-').or(one('+')).may()) .map(rangeofrangeoptrange) .and(numbody.many1()) .map(rangeofrangemany1) .may(), ) .map(rangeofrangeoptrange) .map(|v: Range| { let s: String = input.comstring(v).unwrap(); let v: f64 = s.parse::().unwrap(); JsonVal::Number(v) }) .parse(input.ref_clone()) }

fn stringval(input: CharSpan) -> Option { fn stresc(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.isdigit(16)).unwrapor(false)) .some(4), ) .map(|(, u)| { let s = input.comstring(rangeofmany1(u)).unwrap(); let hex: u32 = u32::fromstrradix(&*s, 16).unwrap(); let c = std::char::fromu32(hex).unwrap(); c })) .map(|v| Result::::Ok(v)) .ortrans(|i: CharSpan, ep| { let loc = i.locrange(ep).unwrap(); Err(JsonParserError { loc, msg: "Illegal escape character".tostring(), }) }) }) .map(|(, v)| v) .parse(input.refclone()) } fn strbody(input: CharSpan) -> Option> { satisfy(|c: Char| c == '' || c == ' ' || c == '\n' || c == '\r' || c == '\t') .map(|i| { let loc = input.locrange(i).unwrap(); Err(JsonParserError { loc, msg: "Control characters are not allowed in the string".tostring(), }) }) .or(stresc) .or(satisfy(|c: Char| c != '"').map(|i| { let s = input.comstring(i).unwrap(); let c = s.chars().next().unwrap(); Ok(c) })) .parse(input.refclone()) } one('"') .and(strbody.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.refclone()) }

fn whitespace(input: CharSpan) -> Option<()> { satisfy(|c: Char| c.iswrap() || 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) .ortrans(|i: CharSpan, ep| { let loc = i.locrange(ep).unwrap(); Err(JsonParserError { loc, msg: "Invaild character".tostring(), }) }) .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(())).ortrans(|i: CharSpan, ep| { let loc = i.locrange(ep); let loc = loc.unwrap(); Err(JsonParserError { loc, msg: "Need \"]\" but not found it".tostring(), }) })) .map( |((, v), e): ((, JsonResults>), JsonResults<()>)| { e?; let v = v?; Ok(JsonVal::Array(v)) }, ) .parse(input) }

fn object(input: CharSpan) -> Option { fn kv(input: CharSpan) -> Optiontrans(|i: CharSpan, ep| { let loc = i.locrange(ep).unwrap(); Err(JsonParserError { loc, msg: "Need \":\" but not found it".tostring(), }) })) .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(())).ortrans(|i: CharSpan, ep| { let loc = i.locrange(ep).unwrap(); Err(JsonParserError { loc, msg: "Need \"}\" but not found it".tostring(), }) })) .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, }

```