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,
}
```