parse anonymous fields
authoralfadur
Mon, 18 May 2020 22:33:13 +0300
changeset 15572 9a333e4e3b50
parent 15571 ae6b09ae4dcc
child 15573 3f388d2e1466
parse anonymous fields
rust/hedgewars-server/src/server/haskell.rs
--- a/rust/hedgewars-server/src/server/haskell.rs	Mon May 18 22:04:38 2020 +0300
+++ b/rust/hedgewars-server/src/server/haskell.rs	Mon May 18 22:33:13 2020 +0300
@@ -1,12 +1,10 @@
 use nom::{
     branch::alt,
-    bytes::complete::{escaped_transform, is_not, tag, take_while},
-    character::is_digit,
-    character::{is_alphanumeric, is_space},
+    bytes::complete::{escaped_transform, is_not, tag, take_while, take_while1},
+    character::{is_alphanumeric, is_digit, is_space},
     combinator::{map, map_res},
     multi::separated_list,
-    sequence::separated_pair,
-    sequence::{delimited, pair},
+    sequence::{delimited, pair, preceded, separated_pair},
     IResult,
 };
 use std::collections::HashMap;
@@ -23,6 +21,10 @@
         name: String,
         fields: HashMap<String, HaskellValue>,
     },
+    AnonStruct {
+        name: String,
+        fields: Vec<HaskellValue>,
+    },
 }
 
 fn comma(input: &[u8]) -> HaskellResult<&[u8]> {
@@ -134,7 +136,7 @@
 }
 
 fn identifier(input: &[u8]) -> HaskellResult<String> {
-    map_res(take_while(is_alphanumeric), |s| {
+    map_res(take_while1(is_alphanumeric), |s| {
         std::str::from_utf8(s).map_err(|_| ()).map(String::from)
     })(input)
 }
@@ -148,16 +150,28 @@
 }
 
 fn structure(input: &[u8]) -> HaskellResult<HaskellValue> {
-    map(
-        pair(
-            identifier,
-            surrounded("{", "}", separated_list(comma, named_field)),
+    alt((
+        map(
+            pair(
+                identifier,
+                surrounded("{", "}", separated_list(comma, named_field)),
+            ),
+            |(name, mut fields)| HaskellValue::Struct {
+                name,
+                fields: fields.drain(..).collect(),
+            },
         ),
-        |(name, mut fields)| HaskellValue::Struct {
-            name,
-            fields: fields.drain(..).collect(),
-        },
-    )(input)
+        map(
+            pair(
+                identifier,
+                preceded(take_while1(is_space), separated_list(comma, value)),
+            ),
+            |(name, mut fields)| HaskellValue::AnonStruct {
+                name: name.clone(),
+                fields,
+            },
+        ),
+    ))(input)
 }
 
 fn value(input: &[u8]) -> HaskellResult<HaskellValue> {
@@ -213,7 +227,17 @@
         };
 
         assert_eq!(
-            structure(b"Hog {name = \"\\240\\159\\166\\148\",health = 100}"),
+            structure(b"Hog {name = \"\\240\\159\\166\\148\", health = 100}"),
+            Ok((&b""[..], value))
+        );
+
+        let value = AnonStruct {
+            name: "Hog".to_string(),
+            fields: vec![Number(100), String("\u{1f994}".to_string())],
+        };
+
+        assert_eq!(
+            structure(b"Hog 100, \"\\240\\159\\166\\148\""),
             Ok((&b""[..], value))
         );
     }