changeset 31:ecfdbe1d1acb

Make JSON parser more lazy. Not constructing parsers when they are not needed saves a lot of time.
author Lewin Bormann <lewin@lewin-bormann.info>
date Thu, 06 Jun 2019 23:53:28 +0200
parents 9ef50316b2e7
children 769ee1b73f31
files examples/json/src/lib.rs src/combinators.rs
diffstat 2 files changed, 44 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/examples/json/src/lib.rs	Thu Jun 06 23:52:51 2019 +0200
+++ b/examples/json/src/lib.rs	Thu Jun 06 23:53:28 2019 +0200
@@ -34,7 +34,7 @@
     ) -> ParseResult<Self::Result> {
         let dict = combinators::Lazy::new(dict);
         let list = combinators::Lazy::new(list);
-        combinators::Alternative::new((string(), number(), dict, list)).parse(st)
+        combinators::Alternative::new((string(), number(), list, dict)).parse(st)
     }
 }
 
@@ -44,7 +44,7 @@
 
 fn string() -> impl Parser<Result = Value> {
     let quote = primitives::StringParser::new("\"");
-    let middle = primitives::string_none_of("\"", combinators::RepeatSpec::Any);
+    let middle = combinators::Lazy::new(|| primitives::string_none_of("\"", combinators::RepeatSpec::Any));
     let string_with_quotes = combinators::Sequence::new((quote.clone(), middle, quote));
     let string = string_with_quotes.apply(|(_, s, _)| Ok(Value::String(s)));
     string
@@ -55,18 +55,21 @@
         primitives::StringParser::new("["),
         primitives::StringParser::new("]"),
     );
-    let val = ValueParser;
-    let comma = primitives::StringParser::new(",");
-    let separated_element = combinators::Sequence::new((
-        primitives::whitespace(),
-        val,
-        primitives::whitespace(),
-        combinators::Maybe::new(comma),
-    ));
-    let separated_element = separated_element.apply(|(_, v, _, _)| Ok(v));
-    let separated_elements =
-        combinators::Repeat::new(separated_element, combinators::RepeatSpec::Any);
-    let list = combinators::Sequence::new((open, separated_elements, close))
+    let inner = || {
+        let val = ValueParser;
+        let comma = primitives::StringParser::new(",");
+        let separated_element = combinators::Sequence::new((
+            primitives::whitespace(),
+            val,
+            primitives::whitespace(),
+            combinators::Maybe::new(comma),
+        ));
+        let separated_element = separated_element.apply(|(_, v, _, _)| Ok(v));
+        let separated_elements =
+            combinators::Repeat::new(separated_element, combinators::RepeatSpec::Any);
+        separated_elements
+    };
+    let list = combinators::Sequence::new((open, combinators::Lazy::new(inner), close))
         .apply(|(_, es, _)| Ok(Value::List(es)));
     list
 }
@@ -76,28 +79,32 @@
         primitives::StringParser::new("{"),
         primitives::StringParser::new("}"),
     );
-    let comma = primitives::StringParser::new(",");
-    let sep = primitives::StringParser::new(":");
-    let key = string().apply(|v| match v {
-        Value::String(s) => Ok(s),
-        _ => panic!("unexpected value type in string position"),
-    });
-    let value = ValueParser;
-    let separated_element = combinators::Sequence::new((
-        primitives::whitespace(),
-        key,
-        primitives::whitespace(),
-        sep,
-        primitives::whitespace(),
-        value,
-        primitives::whitespace(),
-        combinators::Maybe::new(comma),
-    ));
-    let separated_element =
-        separated_element.apply(|(_ws1, k, _ws2, _sep, _ws3, v, _ws4, _comma)| Ok((k, v)));
-    let separated_elements =
-        combinators::Repeat::new(separated_element, combinators::RepeatSpec::Any);
-    let dict = combinators::Sequence::new((open, separated_elements, close))
+
+    let inner = || {
+        let comma = primitives::StringParser::new(",");
+        let sep = primitives::StringParser::new(":");
+        let key = string().apply(|v| match v {
+            Value::String(s) => Ok(s),
+            _ => panic!("unexpected value type in string position"),
+        });
+        let value = ValueParser;
+        let separated_element = combinators::Sequence::new((
+            primitives::whitespace(),
+            key,
+            primitives::whitespace(),
+            sep,
+            primitives::whitespace(),
+            value,
+            primitives::whitespace(),
+            combinators::Maybe::new(comma),
+        ));
+        let separated_element =
+            separated_element.apply(|(_ws1, k, _ws2, _sep, _ws3, v, _ws4, _comma)| Ok((k, v)));
+        let separated_elements =
+            combinators::Repeat::new(separated_element, combinators::RepeatSpec::Any);
+        separated_elements
+    };
+    let dict = combinators::Sequence::new((open, combinators::Lazy::new(inner), close))
         .apply(|(_, es, _)| Ok(Value::Dict(HashMap::from_iter(es.into_iter()))));
     dict
 }
--- a/src/combinators.rs	Thu Jun 06 23:52:51 2019 +0200
+++ b/src/combinators.rs	Thu Jun 06 23:53:28 2019 +0200
@@ -573,7 +573,7 @@
     fn test_lazy3() {
         let mut i = 0;
         let mut ps = ParseState::new("123 124");
-        let mut lzy = || {
+        let lzy = || {
                 assert_eq!(0, i);
                 i += 1;
                 string_of("0123456789", RepeatSpec::Min(1))