Last active
June 25, 2022 15:18
-
-
Save south37/509ba25f32340184ad2981062e41a1e8 to your computer and use it in GitHub Desktop.
Revisions
-
south37 revised this gist
Jul 21, 2018 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,5 @@ // Rewrite code with `parser!` macro. // Target: https://github.com/Marwes/combine/blob/f32fe7c135b8c3104843939b7b505f8b0ea4862e/benches/json.rs #[macro_use] extern crate combine; -
south37 created this gist
Jul 21, 2018 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,214 @@ // Rewrite code with `parser!` macro. // Target: https://github.com/Marwes/combine/blob/master/benches/json.rs #[macro_use] extern crate combine; use std::collections::hash_map::HashMap; use combine::parser::char::{char, string, digit, spaces}; use combine::parser::choice::{choice, optional}; use combine::parser::function::parser; use combine::parser::item::{any, satisfy, satisfy_map}; use combine::parser::repeat::{many, many1, sep_by}; use combine::parser::sequence::between; use combine::{Parser, Stream}; use combine::error::{Consumed, ParseError}; #[derive(PartialEq, Debug)] enum Value { Number(f64), String(String), Bool(bool), Null, Object(HashMap<String, Value>), Array(Vec<Value>), } parser! { fn lex[P](p: P)(P::Input) -> P::Output where [ P: Parser, P::Input: Stream<Item = char> ] { p.skip(spaces()) } } parser! { fn integer[I]()(I) -> i64 where [ I: Stream<Item = char> ] { lex(many1(digit())) .map(|s: String| { let mut n = 0; for c in s.chars() { n = n * 10 + (c as i64 - '0' as i64); } n }) .expected("integer") } } parser! { fn number[I]()(I) -> f64 where [ I: Stream<Item = char> ] { let s = char('-').or(char('+')); let i = integer().map(|x| x as f64); let fractional = many(digit()).map(|digits: String| { let mut magnitude = 1.0; digits.chars().fold(0.0, |acc, d| { magnitude /= 10.0; match d.to_digit(10) { Some(d) => acc + (d as f64) * magnitude, None => panic!("Not a digit"), } }) }); let s2 = char('-').or(char('+')); let exp = satisfy(|c| c == 'e' || c == 'E').with(optional(s2).and(integer())); lex(optional(s) .and(i) .map(|(sign, n)| match sign { Some('-') => { -n } _ => { n } }) .and(optional(char('.')).with(fractional)) .map(|(x, y)| if x >= 0.0 { x + y } else { x - y }) .and(optional(exp)) .map(|(n, exp_option)| match exp_option { Some((sign, e)) => { let e = match sign { Some('-') => { -e } _ => { e } }; n * 10.0f64.powi(e as i32) } None => n, })).expected("number") } } parser! { fn json_char[I]()(I) -> char where [ I: Stream<Item = char> ] { parser(|input: &mut I| { let (c, consumed) = try!(any().parse_lazy(input).into()); let mut back_slash_char = satisfy_map(|c| { Some(match c { '"' => '"', '\\' => '\\', '/' => '/', 'b' => '\u{0008}', 'f' => '\u{000c}', 'n' => '\n', 'r' => '\r', 't' => '\t', _ => return None, }) }); match c { '\\' => consumed.combine(|_| back_slash_char.parse_stream(input)), '"' => Err(Consumed::Empty(I::Error::empty(input.position()).into())), _ => Ok((c, consumed)), } }) } } parser! { fn json_string[I]()(I) -> String where [ I: Stream<Item = char> ] { between(char('"'), lex(char('"')), many(json_char())).expected("string") } } parser! { fn object[I]()(I) -> Value where [ I: Stream<Item = char> ] { let field = (json_string(), lex(char(':')), json_value()).map(|t| (t.0, t.2)); let fields = sep_by(field, lex(char(','))); between(lex(char('{')), lex(char('}')), fields) .map(Value::Object) .expected("object") } } parser! { fn array[I]()(I) -> Value where [ I: Stream<Item = char> ] { let values = sep_by(json_value(), lex(char(','))); between(lex(char('[')), lex(char(']')), values) .map(Value::Array) .expected("array") } } parser! { #[inline(always)] fn json_value[I]()(I) -> Value where [ I: Stream<Item = char> ] { json_value_() } } // We need to use `parser!` to break the recursive use of `value` to prevent the returned parser // from containing itself parser!{ #[inline(always)] fn json_value_[I]()(I) -> Value where [ I: Stream<Item = char> ] { choice(( json_string().map(Value::String), object(), array(), number().map(Value::Number), lex(string("false").map(|_| Value::Bool(false))), lex(string("true").map(|_| Value::Bool(true))), lex(string("null").map(|_| Value::Null)), )) } } fn main() { let mut p = number(); let result = p.parse("-34.56e3"); println!("{:?}", result); println!("{}", result.unwrap().0); let mut p2 = json_string(); let result2 = p2.parse("\"this is json string!\\nGood!\""); println!("{:?}", result2); println!("{}", result2.unwrap().0); let mut p3 = json_value(); let result3 = p3.parse("{ \"key\": [1, 2, 3] }"); println!("{:?}", result3); println!("{:?}", result3.unwrap().0); }