rust/hedgewars-server/src/server/haskell.rs
author alfadur
Tue, 19 May 2020 19:26:48 +0300
changeset 15598 3be9c98ae190
parent 15597 a2e78f5907cc
child 15599 7d4f552e317f
permissions -rw-r--r--
convert teams from haskell list
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
     1
use nom::{
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
     2
    branch::alt,
15594
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
     3
    bytes::complete::{escaped_transform, is_not, tag, take_while, take_while1},
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
     4
    character::{is_alphanumeric, is_digit, is_space},
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
     5
    combinator::{map, map_res},
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
     6
    multi::separated_list,
15594
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
     7
    sequence::{delimited, pair, preceded, separated_pair},
15597
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
     8
    ExtendInto, IResult,
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
     9
};
15596
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    10
use std::{
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    11
    collections::HashMap,
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    12
    fmt::{Display, Error, Formatter},
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    13
};
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    14
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    15
type HaskellResult<'a, T> = IResult<&'a [u8], T, ()>;
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    16
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    17
#[derive(Debug, PartialEq)]
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    18
pub enum HaskellValue {
15596
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    19
    Number(u8),
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    20
    String(String),
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    21
    Tuple(Vec<HaskellValue>),
15596
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    22
    List(Vec<HaskellValue>),
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    23
    AnonStruct {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    24
        name: String,
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    25
        fields: Vec<HaskellValue>,
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    26
    },
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    27
    Struct {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    28
        name: String,
15593
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
    29
        fields: HashMap<String, HaskellValue>,
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    30
    },
15596
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    31
}
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    32
15598
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    33
impl HaskellValue {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    34
    pub fn to_number(&self) -> Option<u8> {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    35
        match self {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    36
            HaskellValue::Number(value) => Some(*value),
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    37
            _ => None,
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    38
        }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    39
    }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    40
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    41
    pub fn into_number(self) -> Option<u8> {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    42
        match self {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    43
            HaskellValue::Number(value) => Some(value),
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    44
            _ => None,
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    45
        }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    46
    }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    47
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    48
    pub fn to_string(&self) -> Option<&str> {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    49
        match self {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    50
            HaskellValue::String(value) => Some(value),
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    51
            _ => None,
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    52
        }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    53
    }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    54
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    55
    pub fn into_string(self) -> Option<String> {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    56
        match self {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    57
            HaskellValue::String(value) => Some(value),
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    58
            _ => None,
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    59
        }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    60
    }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    61
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    62
    pub fn into_list(self) -> Option<Vec<HaskellValue>> {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    63
        match self {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    64
            HaskellValue::List(items) => Some(items),
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    65
            _ => None,
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    66
        }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    67
    }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    68
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    69
    pub fn into_tuple(self) -> Option<Vec<HaskellValue>> {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    70
        match self {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    71
            HaskellValue::Tuple(items) => Some(items),
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    72
            _ => None,
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    73
        }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    74
    }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    75
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    76
    pub fn into_anon_struct(self) -> Option<(String, Vec<HaskellValue>)> {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    77
        match self {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    78
            HaskellValue::AnonStruct { name, fields } => Some((name, fields)),
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    79
            _ => None,
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    80
        }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    81
    }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    82
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    83
    pub fn into_struct(self) -> Option<(String, HashMap<String, HaskellValue>)> {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    84
        match self {
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    85
            HaskellValue::Struct { name, fields } => Some((name, fields)),
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    86
            _ => None,
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    87
        }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    88
    }
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    89
}
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    90
15596
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    91
fn write_sequence(
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    92
    f: &mut Formatter<'_>,
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    93
    brackets: &[u8; 2],
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    94
    mut items: std::slice::Iter<HaskellValue>,
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    95
) -> Result<(), Error> {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    96
    write!(f, "{}", brackets[0] as char)?;
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    97
    while let Some(value) = items.next() {
15598
3be9c98ae190 convert teams from haskell list
alfadur
parents: 15597
diff changeset
    98
        write!(f, "{}", value)?;
15596
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
    99
        if !items.as_slice().is_empty() {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   100
            write!(f, ", ")?;
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   101
        }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   102
    }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   103
    if brackets[1] != b'\0' {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   104
        write!(f, "{}", brackets[1] as char)
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   105
    } else {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   106
        Ok(())
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   107
    }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   108
}
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   109
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   110
fn write_text(f: &mut Formatter<'_>, text: &str) -> Result<(), Error> {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   111
    write!(f, "\"")?;
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   112
    for c in text.chars() {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   113
        if c.is_ascii() && !(c as u8).is_ascii_control() {
15597
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   114
            write!(f, "{}", c)?;
15596
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   115
        } else {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   116
            let mut bytes = [0u8; 4];
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   117
            let size = c.encode_utf8(&mut bytes).len();
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   118
            for byte in &bytes[0..size] {
15597
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   119
                write!(f, "\\{:03}", byte)?;
15596
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   120
            }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   121
        }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   122
    }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   123
    write!(f, "\"")
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   124
}
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   125
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   126
impl Display for HaskellValue {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   127
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   128
        match self {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   129
            HaskellValue::Number(value) => write!(f, "{}", value),
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   130
            HaskellValue::String(value) => write_text(f, value),
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   131
            HaskellValue::Tuple(items) => write_sequence(f, b"()", items.iter()),
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   132
            HaskellValue::List(items) => write_sequence(f, b"[]", items.iter()),
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   133
            HaskellValue::AnonStruct { name, fields } => {
15597
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   134
                write!(f, "{} ", name)?;
15596
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   135
                write_sequence(f, b" \0", fields.iter())
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   136
            }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   137
            HaskellValue::Struct { name, fields } => {
15597
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   138
                write!(f, "{} {{", name)?;
15596
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   139
                let fields = fields.iter().collect::<Vec<_>>();
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   140
                let mut items = fields.iter();
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   141
                while let Some((field_name, value)) = items.next() {
15597
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   142
                    write!(f, "{} = {}", field_name, value)?;
15596
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   143
                    if !items.as_slice().is_empty() {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   144
                        write!(f, ", ")?;
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   145
                    }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   146
                }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   147
                write!(f, "}}")
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   148
            }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   149
        }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15595
diff changeset
   150
    }
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   151
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   152
15593
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   153
fn comma(input: &[u8]) -> HaskellResult<&[u8]> {
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   154
    delimited(take_while(is_space), tag(","), take_while(is_space))(input)
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   155
}
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   156
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   157
fn surrounded<'a, P, O>(
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   158
    prefix: &'static str,
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   159
    suffix: &'static str,
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   160
    parser: P,
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   161
) -> impl Fn(&'a [u8]) -> HaskellResult<'a, O>
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   162
where
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   163
    P: Fn(&'a [u8]) -> HaskellResult<'a, O>,
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   164
{
15593
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   165
    move |input| {
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   166
        delimited(
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   167
            delimited(take_while(is_space), tag(prefix), take_while(is_space)),
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   168
            |i| parser(i),
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   169
            delimited(take_while(is_space), tag(suffix), take_while(is_space)),
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   170
        )(input)
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   171
    }
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   172
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   173
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   174
fn number_raw(input: &[u8]) -> HaskellResult<u8> {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   175
    use std::str::FromStr;
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   176
    map_res(take_while(is_digit), |s| {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   177
        std::str::from_utf8(s)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   178
            .map_err(|_| ())
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   179
            .and_then(|s| u8::from_str(s).map_err(|_| ()))
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   180
    })(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   181
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   182
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   183
fn number(input: &[u8]) -> HaskellResult<HaskellValue> {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   184
    map(number_raw, HaskellValue::Number)(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   185
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   186
15597
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   187
enum Escape {
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   188
    Empty,
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   189
    Byte(u8),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   190
}
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   191
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   192
impl ExtendInto for Escape {
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   193
    type Item = u8;
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   194
    type Extender = Vec<u8>;
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   195
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   196
    fn new_builder(&self) -> Self::Extender {
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   197
        Vec::new()
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   198
    }
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   199
15597
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   200
    fn extend_into(&self, acc: &mut Self::Extender) {
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   201
        if let Escape::Byte(b) = self {
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   202
            acc.push(*b);
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   203
        }
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   204
    }
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   205
}
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   206
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   207
impl Extend<Escape> for Vec<u8> {
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   208
    fn extend<T: IntoIterator<Item = Escape>>(&mut self, iter: T) {
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   209
        for item in iter {
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   210
            item.extend_into(self);
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   211
        }
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   212
    }
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   213
}
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   214
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   215
fn string_escape(input: &[u8]) -> HaskellResult<Escape> {
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   216
    use Escape::*;
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   217
    alt((
15597
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   218
        map(number_raw, |n| Byte(n)),
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   219
        alt((
15597
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   220
            map(tag("\\"), |_| Byte(b'\\')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   221
            map(tag("\""), |_| Byte(b'\"')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   222
            map(tag("'"), |_| Byte(b'\'')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   223
            map(tag("n"), |_| Byte(b'\n')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   224
            map(tag("r"), |_| Byte(b'\r')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   225
            map(tag("t"), |_| Byte(b'\t')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   226
            map(tag("a"), |_| Byte(b'\x07')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   227
            map(tag("b"), |_| Byte(b'\x08')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   228
            map(tag("v"), |_| Byte(b'\x0B')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   229
            map(tag("f"), |_| Byte(b'\x0C')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   230
            map(tag("&"), |_| Empty),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   231
            map(tag("NUL"), |_| Byte(b'\x00')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   232
            map(tag("SOH"), |_| Byte(b'\x01')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   233
            map(tag("STX"), |_| Byte(b'\x02')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   234
            map(tag("ETX"), |_| Byte(b'\x03')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   235
            map(tag("EOT"), |_| Byte(b'\x04')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   236
            map(tag("ENQ"), |_| Byte(b'\x05')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   237
            map(tag("ACK"), |_| Byte(b'\x06')),
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   238
        )),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   239
        alt((
15597
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   240
            map(tag("SO"), |_| Byte(b'\x0E')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   241
            map(tag("SI"), |_| Byte(b'\x0F')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   242
            map(tag("DLE"), |_| Byte(b'\x10')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   243
            map(tag("DC1"), |_| Byte(b'\x11')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   244
            map(tag("DC2"), |_| Byte(b'\x12')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   245
            map(tag("DC3"), |_| Byte(b'\x13')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   246
            map(tag("DC4"), |_| Byte(b'\x14')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   247
            map(tag("NAK"), |_| Byte(b'\x15')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   248
            map(tag("SYN"), |_| Byte(b'\x16')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   249
            map(tag("ETB"), |_| Byte(b'\x17')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   250
            map(tag("CAN"), |_| Byte(b'\x18')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   251
            map(tag("EM"), |_| Byte(b'\x19')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   252
            map(tag("SUB"), |_| Byte(b'\x1A')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   253
            map(tag("ESC"), |_| Byte(b'\x1B')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   254
            map(tag("FS"), |_| Byte(b'\x1C')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   255
            map(tag("GS"), |_| Byte(b'\x1D')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   256
            map(tag("RS"), |_| Byte(b'\x1E')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   257
            map(tag("US"), |_| Byte(b'\x1F')),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   258
            map(tag("DEL"), |_| Byte(b'\x7F')),
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   259
        )),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   260
    ))(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   261
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   262
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   263
fn string_content(mut input: &[u8]) -> HaskellResult<String> {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   264
    map_res(
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   265
        escaped_transform(is_not("\"\\"), '\\', string_escape),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   266
        |bytes| String::from_utf8(bytes).map_err(|_| ()),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   267
    )(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   268
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   269
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   270
fn string(input: &[u8]) -> HaskellResult<HaskellValue> {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   271
    map(surrounded("\"", "\"", string_content), HaskellValue::String)(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   272
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   273
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   274
fn tuple(input: &[u8]) -> HaskellResult<HaskellValue> {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   275
    map(
15593
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   276
        surrounded("(", ")", separated_list(comma, value)),
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   277
        HaskellValue::Tuple,
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   278
    )(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   279
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   280
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   281
fn list(input: &[u8]) -> HaskellResult<HaskellValue> {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   282
    map(
15593
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   283
        surrounded("[", "]", separated_list(comma, value)),
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   284
        HaskellValue::List,
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   285
    )(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   286
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   287
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   288
fn identifier(input: &[u8]) -> HaskellResult<String> {
15594
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   289
    map_res(take_while1(is_alphanumeric), |s| {
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   290
        std::str::from_utf8(s).map_err(|_| ()).map(String::from)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   291
    })(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   292
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   293
15593
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   294
fn named_field(input: &[u8]) -> HaskellResult<(String, HaskellValue)> {
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   295
    separated_pair(
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   296
        identifier,
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   297
        delimited(take_while(is_space), tag("="), take_while(is_space)),
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   298
        value,
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   299
    )(input)
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   300
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   301
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   302
fn structure(input: &[u8]) -> HaskellResult<HaskellValue> {
15594
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   303
    alt((
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   304
        map(
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   305
            pair(
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   306
                identifier,
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   307
                surrounded("{", "}", separated_list(comma, named_field)),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   308
            ),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   309
            |(name, mut fields)| HaskellValue::Struct {
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   310
                name,
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   311
                fields: fields.drain(..).collect(),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   312
            },
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   313
        ),
15594
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   314
        map(
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   315
            pair(
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   316
                identifier,
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   317
                preceded(take_while1(is_space), separated_list(comma, value)),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   318
            ),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   319
            |(name, mut fields)| HaskellValue::AnonStruct {
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   320
                name: name.clone(),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   321
                fields,
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   322
            },
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   323
        ),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   324
    ))(input)
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   325
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   326
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   327
fn value(input: &[u8]) -> HaskellResult<HaskellValue> {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   328
    alt((number, string, tuple, list, structure))(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   329
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   330
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   331
#[inline]
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   332
pub fn parse(input: &[u8]) -> HaskellResult<HaskellValue> {
15593
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   333
    delimited(take_while(is_space), value, take_while(is_space))(input)
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   334
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   335
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   336
mod test {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   337
    use super::*;
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   338
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   339
    #[test]
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   340
    fn terminals() {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   341
        use HaskellValue::*;
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   342
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   343
        matches!(number(b"127"), Ok((_, Number(127))));
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   344
        matches!(number(b"adas"), Err(nom::Err::Error(())));
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   345
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   346
        assert_eq!(
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   347
            string(b"\"Hail \\240\\159\\166\\148!\""),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   348
            Ok((&b""[..], String("Hail \u{1f994}!".to_string())))
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   349
        );
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   350
    }
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   351
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   352
    #[test]
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   353
    fn sequences() {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   354
        use HaskellValue::*;
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   355
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   356
        let value = Tuple(vec![
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   357
            Number(64),
15597
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   358
            String("text\t1".to_string()),
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   359
            List(vec![Number(1), Number(2), Number(3)]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   360
        ]);
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   361
15597
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   362
        assert_eq!(
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   363
            tuple(b"(64, \"text\\t1\", [1 , 2, 3])"),
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   364
            Ok((&b""[..], value))
a2e78f5907cc improve escapes handling
alfadur
parents: 15596
diff changeset
   365
        );
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   366
    }
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   367
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   368
    #[test]
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   369
    fn structures() {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   370
        use HaskellValue::*;
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   371
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   372
        let value = Struct {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   373
            name: "Hog".to_string(),
15593
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15592
diff changeset
   374
            fields: vec![
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   375
                ("name".to_string(), String("\u{1f994}".to_string())),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   376
                ("health".to_string(), Number(100)),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   377
            ]
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   378
            .drain(..)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   379
            .collect(),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   380
        };
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   381
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   382
        assert_eq!(
15594
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   383
            structure(b"Hog {name = \"\\240\\159\\166\\148\", health = 100}"),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   384
            Ok((&b""[..], value))
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   385
        );
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   386
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   387
        let value = AnonStruct {
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   388
            name: "Hog".to_string(),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   389
            fields: vec![Number(100), String("\u{1f994}".to_string())],
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   390
        };
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   391
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   392
        assert_eq!(
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15593
diff changeset
   393
            structure(b"Hog 100, \"\\240\\159\\166\\148\""),
15592
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   394
            Ok((&b""[..], value))
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   395
        );
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   396
    }
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   397
}