rust/hedgewars-server/src/server/haskell.rs
changeset 15594 9a333e4e3b50
parent 15593 ae6b09ae4dcc
child 15595 3f388d2e1466
equal deleted inserted replaced
15593:ae6b09ae4dcc 15594:9a333e4e3b50
     1 use nom::{
     1 use nom::{
     2     branch::alt,
     2     branch::alt,
     3     bytes::complete::{escaped_transform, is_not, tag, take_while},
     3     bytes::complete::{escaped_transform, is_not, tag, take_while, take_while1},
     4     character::is_digit,
     4     character::{is_alphanumeric, is_digit, is_space},
     5     character::{is_alphanumeric, is_space},
       
     6     combinator::{map, map_res},
     5     combinator::{map, map_res},
     7     multi::separated_list,
     6     multi::separated_list,
     8     sequence::separated_pair,
     7     sequence::{delimited, pair, preceded, separated_pair},
     9     sequence::{delimited, pair},
       
    10     IResult,
     8     IResult,
    11 };
     9 };
    12 use std::collections::HashMap;
    10 use std::collections::HashMap;
    13 
    11 
    14 type HaskellResult<'a, T> = IResult<&'a [u8], T, ()>;
    12 type HaskellResult<'a, T> = IResult<&'a [u8], T, ()>;
    20     String(String),
    18     String(String),
    21     Number(u8),
    19     Number(u8),
    22     Struct {
    20     Struct {
    23         name: String,
    21         name: String,
    24         fields: HashMap<String, HaskellValue>,
    22         fields: HashMap<String, HaskellValue>,
       
    23     },
       
    24     AnonStruct {
       
    25         name: String,
       
    26         fields: Vec<HaskellValue>,
    25     },
    27     },
    26 }
    28 }
    27 
    29 
    28 fn comma(input: &[u8]) -> HaskellResult<&[u8]> {
    30 fn comma(input: &[u8]) -> HaskellResult<&[u8]> {
    29     delimited(take_while(is_space), tag(","), take_while(is_space))(input)
    31     delimited(take_while(is_space), tag(","), take_while(is_space))(input)
   132         HaskellValue::List,
   134         HaskellValue::List,
   133     )(input)
   135     )(input)
   134 }
   136 }
   135 
   137 
   136 fn identifier(input: &[u8]) -> HaskellResult<String> {
   138 fn identifier(input: &[u8]) -> HaskellResult<String> {
   137     map_res(take_while(is_alphanumeric), |s| {
   139     map_res(take_while1(is_alphanumeric), |s| {
   138         std::str::from_utf8(s).map_err(|_| ()).map(String::from)
   140         std::str::from_utf8(s).map_err(|_| ()).map(String::from)
   139     })(input)
   141     })(input)
   140 }
   142 }
   141 
   143 
   142 fn named_field(input: &[u8]) -> HaskellResult<(String, HaskellValue)> {
   144 fn named_field(input: &[u8]) -> HaskellResult<(String, HaskellValue)> {
   146         value,
   148         value,
   147     )(input)
   149     )(input)
   148 }
   150 }
   149 
   151 
   150 fn structure(input: &[u8]) -> HaskellResult<HaskellValue> {
   152 fn structure(input: &[u8]) -> HaskellResult<HaskellValue> {
   151     map(
   153     alt((
   152         pair(
   154         map(
   153             identifier,
   155             pair(
   154             surrounded("{", "}", separated_list(comma, named_field)),
   156                 identifier,
       
   157                 surrounded("{", "}", separated_list(comma, named_field)),
       
   158             ),
       
   159             |(name, mut fields)| HaskellValue::Struct {
       
   160                 name,
       
   161                 fields: fields.drain(..).collect(),
       
   162             },
   155         ),
   163         ),
   156         |(name, mut fields)| HaskellValue::Struct {
   164         map(
   157             name,
   165             pair(
   158             fields: fields.drain(..).collect(),
   166                 identifier,
   159         },
   167                 preceded(take_while1(is_space), separated_list(comma, value)),
   160     )(input)
   168             ),
       
   169             |(name, mut fields)| HaskellValue::AnonStruct {
       
   170                 name: name.clone(),
       
   171                 fields,
       
   172             },
       
   173         ),
       
   174     ))(input)
   161 }
   175 }
   162 
   176 
   163 fn value(input: &[u8]) -> HaskellResult<HaskellValue> {
   177 fn value(input: &[u8]) -> HaskellResult<HaskellValue> {
   164     alt((number, string, tuple, list, structure))(input)
   178     alt((number, string, tuple, list, structure))(input)
   165 }
   179 }
   211             .drain(..)
   225             .drain(..)
   212             .collect(),
   226             .collect(),
   213         };
   227         };
   214 
   228 
   215         assert_eq!(
   229         assert_eq!(
   216             structure(b"Hog {name = \"\\240\\159\\166\\148\",health = 100}"),
   230             structure(b"Hog {name = \"\\240\\159\\166\\148\", health = 100}"),
   217             Ok((&b""[..], value))
   231             Ok((&b""[..], value))
   218         );
   232         );
   219     }
   233 
   220 }
   234         let value = AnonStruct {
       
   235             name: "Hog".to_string(),
       
   236             fields: vec![Number(100), String("\u{1f994}".to_string())],
       
   237         };
       
   238 
       
   239         assert_eq!(
       
   240             structure(b"Hog 100, \"\\240\\159\\166\\148\""),
       
   241             Ok((&b""[..], value))
       
   242         );
       
   243     }
       
   244 }