rust/hedgewars-server/src/server/haskell.rs
changeset 15571 ae6b09ae4dcc
parent 15570 d524b7450576
child 15572 9a333e4e3b50
equal deleted inserted replaced
15570:d524b7450576 15571:ae6b09ae4dcc
     1 use nom::character::is_alphanumeric;
       
     2 use nom::{
     1 use nom::{
     3     branch::alt,
     2     branch::alt,
     4     bytes::{
     3     bytes::complete::{escaped_transform, is_not, tag, take_while},
     5         complete::tag,
       
     6         complete::take_while,
       
     7         complete::{escaped_transform, is_not},
       
     8     },
       
     9     character::is_digit,
     4     character::is_digit,
       
     5     character::{is_alphanumeric, is_space},
    10     combinator::{map, map_res},
     6     combinator::{map, map_res},
    11     multi::separated_list,
     7     multi::separated_list,
       
     8     sequence::separated_pair,
    12     sequence::{delimited, pair},
     9     sequence::{delimited, pair},
    13     IResult,
    10     IResult,
    14 };
    11 };
    15 use std::collections::HashMap;
    12 use std::collections::HashMap;
    16 
    13 
    22     Tuple(Vec<HaskellValue>),
    19     Tuple(Vec<HaskellValue>),
    23     String(String),
    20     String(String),
    24     Number(u8),
    21     Number(u8),
    25     Struct {
    22     Struct {
    26         name: String,
    23         name: String,
    27         values: HashMap<String, HaskellValue>,
    24         fields: HashMap<String, HaskellValue>,
    28     },
    25     },
       
    26 }
       
    27 
       
    28 fn comma(input: &[u8]) -> HaskellResult<&[u8]> {
       
    29     delimited(take_while(is_space), tag(","), take_while(is_space))(input)
    29 }
    30 }
    30 
    31 
    31 fn surrounded<'a, P, O>(
    32 fn surrounded<'a, P, O>(
    32     prefix: &'static str,
    33     prefix: &'static str,
    33     suffix: &'static str,
    34     suffix: &'static str,
    34     parser: P,
    35     parser: P,
    35 ) -> impl Fn(&'a [u8]) -> HaskellResult<'a, O>
    36 ) -> impl Fn(&'a [u8]) -> HaskellResult<'a, O>
    36 where
    37 where
    37     P: Fn(&'a [u8]) -> HaskellResult<'a, O>,
    38     P: Fn(&'a [u8]) -> HaskellResult<'a, O>,
    38 {
    39 {
    39     move |input| delimited(tag(prefix), |i| parser(i), tag(suffix))(input)
    40     move |input| {
       
    41         delimited(
       
    42             delimited(take_while(is_space), tag(prefix), take_while(is_space)),
       
    43             |i| parser(i),
       
    44             delimited(take_while(is_space), tag(suffix), take_while(is_space)),
       
    45         )(input)
       
    46     }
    40 }
    47 }
    41 
    48 
    42 fn number_raw(input: &[u8]) -> HaskellResult<u8> {
    49 fn number_raw(input: &[u8]) -> HaskellResult<u8> {
    43     use std::str::FromStr;
    50     use std::str::FromStr;
    44     map_res(take_while(is_digit), |s| {
    51     map_res(take_while(is_digit), |s| {
    48     })(input)
    55     })(input)
    49 }
    56 }
    50 
    57 
    51 fn number(input: &[u8]) -> HaskellResult<HaskellValue> {
    58 fn number(input: &[u8]) -> HaskellResult<HaskellValue> {
    52     map(number_raw, HaskellValue::Number)(input)
    59     map(number_raw, HaskellValue::Number)(input)
    53 }
       
    54 
       
    55 fn read_string(input: &[u8]) -> HaskellResult<String> {
       
    56     Ok((input, String::new()))
       
    57 }
       
    58 
       
    59 fn raw_string_part(input: &[u8]) -> HaskellResult<&[u8]> {
       
    60     take_while(|c| !b"\"\\".contains(&c))(input)
       
    61 }
    60 }
    62 
    61 
    63 const BYTES: &[u8] = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";
    62 const BYTES: &[u8] = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";
    64 
    63 
    65 fn string_escape(input: &[u8]) -> HaskellResult<&[u8]> {
    64 fn string_escape(input: &[u8]) -> HaskellResult<&[u8]> {
   120     map(surrounded("\"", "\"", string_content), HaskellValue::String)(input)
   119     map(surrounded("\"", "\"", string_content), HaskellValue::String)(input)
   121 }
   120 }
   122 
   121 
   123 fn tuple(input: &[u8]) -> HaskellResult<HaskellValue> {
   122 fn tuple(input: &[u8]) -> HaskellResult<HaskellValue> {
   124     map(
   123     map(
   125         surrounded("(", ")", separated_list(tag(","), value)),
   124         surrounded("(", ")", separated_list(comma, value)),
   126         HaskellValue::Tuple,
   125         HaskellValue::Tuple,
   127     )(input)
   126     )(input)
   128 }
   127 }
   129 
   128 
   130 fn list(input: &[u8]) -> HaskellResult<HaskellValue> {
   129 fn list(input: &[u8]) -> HaskellResult<HaskellValue> {
   131     map(
   130     map(
   132         surrounded("[", "]", separated_list(tag(","), value)),
   131         surrounded("[", "]", separated_list(comma, value)),
   133         HaskellValue::List,
   132         HaskellValue::List,
   134     )(input)
   133     )(input)
   135 }
   134 }
   136 
   135 
   137 fn identifier(input: &[u8]) -> HaskellResult<String> {
   136 fn identifier(input: &[u8]) -> HaskellResult<String> {
   138     map_res(take_while(is_alphanumeric), |s| {
   137     map_res(take_while(is_alphanumeric), |s| {
   139         std::str::from_utf8(s).map_err(|_| ()).map(String::from)
   138         std::str::from_utf8(s).map_err(|_| ()).map(String::from)
   140     })(input)
   139     })(input)
   141 }
   140 }
   142 
   141 
   143 fn property() -> impl Fn(&[u8]) -> HaskellResult<(String, HaskellValue)> {
   142 fn named_field(input: &[u8]) -> HaskellResult<(String, HaskellValue)> {
   144     |input| {
   143     separated_pair(
   145         let (input, name) = identifier(input)?;
   144         identifier,
   146         let (input, _) = tag("=")(input)?;
   145         delimited(take_while(is_space), tag("="), take_while(is_space)),
   147         value(input).map(|(i, value)| (i, (name, value)))
   146         value,
   148     }
   147     )(input)
   149 }
   148 }
   150 
   149 
   151 fn structure(input: &[u8]) -> HaskellResult<HaskellValue> {
   150 fn structure(input: &[u8]) -> HaskellResult<HaskellValue> {
   152     map(
   151     map(
   153         pair(
   152         pair(
   154             identifier,
   153             identifier,
   155             surrounded("{", "}", separated_list(tag(","), property())),
   154             surrounded("{", "}", separated_list(comma, named_field)),
   156         ),
   155         ),
   157         |(name, mut values)| HaskellValue::Struct {
   156         |(name, mut fields)| HaskellValue::Struct {
   158             name,
   157             name,
   159             values: values.drain(..).collect(),
   158             fields: fields.drain(..).collect(),
   160         },
   159         },
   161     )(input)
   160     )(input)
   162 }
   161 }
   163 
   162 
   164 fn value(input: &[u8]) -> HaskellResult<HaskellValue> {
   163 fn value(input: &[u8]) -> HaskellResult<HaskellValue> {
   165     alt((number, string, tuple, list, structure))(input)
   164     alt((number, string, tuple, list, structure))(input)
   166 }
   165 }
   167 
   166 
   168 #[inline]
   167 #[inline]
   169 pub fn parse(input: &[u8]) -> HaskellResult<HaskellValue> {
   168 pub fn parse(input: &[u8]) -> HaskellResult<HaskellValue> {
   170     value(input)
   169     delimited(take_while(is_space), value, take_while(is_space))(input)
   171 }
   170 }
   172 
   171 
   173 mod test {
   172 mod test {
   174     use super::*;
   173     use super::*;
   175 
   174 
   194             Number(64),
   193             Number(64),
   195             String("text".to_string()),
   194             String("text".to_string()),
   196             List(vec![Number(1), Number(2), Number(3)]),
   195             List(vec![Number(1), Number(2), Number(3)]),
   197         ]);
   196         ]);
   198 
   197 
   199         assert_eq!(tuple(b"(64,\"text\",[1,2,3])"), Ok((&b""[..], value)));
   198         assert_eq!(tuple(b"(64, \"text\", [1 , 2, 3])"), Ok((&b""[..], value)));
   200     }
   199     }
   201 
   200 
   202     #[test]
   201     #[test]
   203     fn structures() {
   202     fn structures() {
   204         use HaskellValue::*;
   203         use HaskellValue::*;
   205 
   204 
   206         let value = Struct {
   205         let value = Struct {
   207             name: "Hog".to_string(),
   206             name: "Hog".to_string(),
   208             values: vec![
   207             fields: vec![
   209                 ("name".to_string(), String("\u{1f994}".to_string())),
   208                 ("name".to_string(), String("\u{1f994}".to_string())),
   210                 ("health".to_string(), Number(100)),
   209                 ("health".to_string(), Number(100)),
   211             ]
   210             ]
   212             .drain(..)
   211             .drain(..)
   213             .collect(),
   212             .collect(),
   214         };
   213         };
   215 
   214 
   216         assert_eq!(
   215         assert_eq!(
   217             structure(b"Hog{name=\"\\240\\159\\166\\148\",health=100}"),
   216             structure(b"Hog {name = \"\\240\\159\\166\\148\",health = 100}"),
   218             Ok((&b""[..], value))
   217             Ok((&b""[..], value))
   219         );
   218         );
   220     }
   219     }
   221 }
   220 }