rust/hedgewars-server/src/server/haskell.rs
author alfadur
Mon, 18 May 2020 23:43:58 +0300
changeset 15574 ca5c7c1de985
parent 15573 3f388d2e1466
child 15575 a2e78f5907cc
permissions -rw-r--r--
add haskell literal formatter
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
     1
use nom::{
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
     2
    branch::alt,
15572
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
     3
    bytes::complete::{escaped_transform, is_not, tag, take_while, take_while1},
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
     4
    character::{is_alphanumeric, is_digit, is_space},
15570
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,
15572
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
     7
    sequence::{delimited, pair, preceded, separated_pair},
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
     8
    IResult,
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
     9
};
15574
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    10
use std::{
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    11
    collections::HashMap,
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    12
    fmt::{Display, Error, Formatter},
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    13
};
15570
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 {
15574
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    19
    Number(u8),
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    20
    String(String),
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    21
    Tuple(Vec<HaskellValue>),
15574
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    22
    List(Vec<HaskellValue>),
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    23
    AnonStruct {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    24
        name: String,
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    25
        fields: Vec<HaskellValue>,
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    26
    },
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    27
    Struct {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    28
        name: String,
15571
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
    29
        fields: HashMap<String, HaskellValue>,
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    30
    },
15574
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    31
}
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    32
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    33
fn write_sequence(
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    34
    f: &mut Formatter<'_>,
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    35
    brackets: &[u8; 2],
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    36
    mut items: std::slice::Iter<HaskellValue>,
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    37
) -> Result<(), Error> {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    38
    write!(f, "{}", brackets[0] as char)?;
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    39
    while let Some(value) = items.next() {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    40
        write!(f, "{}", value);
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    41
        if !items.as_slice().is_empty() {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    42
            write!(f, ", ")?;
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    43
        }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    44
    }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    45
    if brackets[1] != b'\0' {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    46
        write!(f, "{}", brackets[1] as char)
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    47
    } else {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    48
        Ok(())
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    49
    }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    50
}
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    51
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    52
fn write_text(f: &mut Formatter<'_>, text: &str) -> Result<(), Error> {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    53
    write!(f, "\"")?;
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    54
    for c in text.chars() {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    55
        if c.is_ascii() && !(c as u8).is_ascii_control() {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    56
            write!(f, "{}", c);
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    57
        } else {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    58
            let mut bytes = [0u8; 4];
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    59
            let size = c.encode_utf8(&mut bytes).len();
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    60
            for byte in &bytes[0..size] {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    61
                write!(f, "\\{:03}", byte);
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    62
            }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    63
        }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    64
    }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    65
    write!(f, "\"")
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    66
}
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    67
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    68
impl Display for HaskellValue {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    69
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    70
        match self {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    71
            HaskellValue::Number(value) => write!(f, "{}", value),
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    72
            HaskellValue::String(value) => write_text(f, value),
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    73
            HaskellValue::Tuple(items) => write_sequence(f, b"()", items.iter()),
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    74
            HaskellValue::List(items) => write_sequence(f, b"[]", items.iter()),
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    75
            HaskellValue::AnonStruct { name, fields } => {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    76
                write!(f, "{} ", name);
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    77
                write_sequence(f, b" \0", fields.iter())
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    78
            }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    79
            HaskellValue::Struct { name, fields } => {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    80
                write!(f, "{} {{", name);
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    81
                let fields = fields.iter().collect::<Vec<_>>();
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    82
                let mut items = fields.iter();
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    83
                while let Some((field_name, value)) = items.next() {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    84
                    write!(f, "{} = {}", field_name, value);
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    85
                    if !items.as_slice().is_empty() {
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    86
                        write!(f, ", ")?;
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    87
                    }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    88
                }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    89
                write!(f, "}}")
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    90
            }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    91
        }
ca5c7c1de985 add haskell literal formatter
alfadur
parents: 15573
diff changeset
    92
    }
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    93
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    94
15571
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
    95
fn comma(input: &[u8]) -> HaskellResult<&[u8]> {
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
    96
    delimited(take_while(is_space), tag(","), take_while(is_space))(input)
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
    97
}
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
    98
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
    99
fn surrounded<'a, P, O>(
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   100
    prefix: &'static str,
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   101
    suffix: &'static str,
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   102
    parser: P,
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   103
) -> impl Fn(&'a [u8]) -> HaskellResult<'a, O>
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   104
where
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   105
    P: Fn(&'a [u8]) -> HaskellResult<'a, O>,
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   106
{
15571
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   107
    move |input| {
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   108
        delimited(
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   109
            delimited(take_while(is_space), tag(prefix), take_while(is_space)),
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   110
            |i| parser(i),
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   111
            delimited(take_while(is_space), tag(suffix), take_while(is_space)),
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   112
        )(input)
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   113
    }
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   114
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   115
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   116
fn number_raw(input: &[u8]) -> HaskellResult<u8> {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   117
    use std::str::FromStr;
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   118
    map_res(take_while(is_digit), |s| {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   119
        std::str::from_utf8(s)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   120
            .map_err(|_| ())
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   121
            .and_then(|s| u8::from_str(s).map_err(|_| ()))
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   122
    })(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   123
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   124
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   125
fn number(input: &[u8]) -> HaskellResult<HaskellValue> {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   126
    map(number_raw, HaskellValue::Number)(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   127
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   128
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   129
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";
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   130
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   131
fn string_escape(input: &[u8]) -> HaskellResult<&[u8]> {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   132
    alt((
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   133
        map(number_raw, |n| &BYTES[n as usize..(n + 1) as usize]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   134
        alt((
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   135
            map(tag("\\"), |_| &b"\\"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   136
            map(tag("\""), |_| &b"\""[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   137
            map(tag("'"), |_| &b"'"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   138
            map(tag("n"), |_| &b"\n"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   139
            map(tag("r"), |_| &b"\r"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   140
            map(tag("t"), |_| &b"\t"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   141
            map(tag("a"), |_| &b"\x07"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   142
            map(tag("b"), |_| &b"\x08"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   143
            map(tag("v"), |_| &b"\x0B"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   144
            map(tag("f"), |_| &b"\x0C"[..]),
15573
3f388d2e1466 add the empty escape
alfadur
parents: 15572
diff changeset
   145
            map(tag("&"), |_| &b""[..]),
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   146
            map(tag("NUL"), |_| &b"\x00"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   147
            map(tag("SOH"), |_| &b"\x01"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   148
            map(tag("STX"), |_| &b"\x02"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   149
            map(tag("ETX"), |_| &b"\x03"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   150
            map(tag("EOT"), |_| &b"\x04"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   151
            map(tag("ENQ"), |_| &b"\x05"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   152
            map(tag("ACK"), |_| &b"\x06"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   153
        )),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   154
        alt((
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   155
            map(tag("SO"), |_| &b"\x0E"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   156
            map(tag("SI"), |_| &b"\x0F"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   157
            map(tag("DLE"), |_| &b"\x10"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   158
            map(tag("DC1"), |_| &b"\x11"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   159
            map(tag("DC2"), |_| &b"\x12"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   160
            map(tag("DC3"), |_| &b"\x13"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   161
            map(tag("DC4"), |_| &b"\x14"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   162
            map(tag("NAK"), |_| &b"\x15"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   163
            map(tag("SYN"), |_| &b"\x16"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   164
            map(tag("ETB"), |_| &b"\x17"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   165
            map(tag("CAN"), |_| &b"\x18"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   166
            map(tag("EM"), |_| &b"\x19"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   167
            map(tag("SUB"), |_| &b"\x1A"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   168
            map(tag("ESC"), |_| &b"\x1B"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   169
            map(tag("FS"), |_| &b"\x1C"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   170
            map(tag("GS"), |_| &b"\x1D"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   171
            map(tag("RS"), |_| &b"\x1E"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   172
            map(tag("US"), |_| &b"\x1F"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   173
            map(tag("DEL"), |_| &b"\x7F"[..]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   174
        )),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   175
    ))(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   176
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   177
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   178
fn string_content(mut input: &[u8]) -> HaskellResult<String> {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   179
    map_res(
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   180
        escaped_transform(is_not("\"\\"), '\\', string_escape),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   181
        |bytes| String::from_utf8(bytes).map_err(|_| ()),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   182
    )(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   183
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   184
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   185
fn string(input: &[u8]) -> HaskellResult<HaskellValue> {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   186
    map(surrounded("\"", "\"", string_content), HaskellValue::String)(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   187
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   188
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   189
fn tuple(input: &[u8]) -> HaskellResult<HaskellValue> {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   190
    map(
15571
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   191
        surrounded("(", ")", separated_list(comma, value)),
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   192
        HaskellValue::Tuple,
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   193
    )(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   194
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   195
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   196
fn list(input: &[u8]) -> HaskellResult<HaskellValue> {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   197
    map(
15571
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   198
        surrounded("[", "]", separated_list(comma, value)),
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   199
        HaskellValue::List,
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   200
    )(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   201
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   202
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   203
fn identifier(input: &[u8]) -> HaskellResult<String> {
15572
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   204
    map_res(take_while1(is_alphanumeric), |s| {
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   205
        std::str::from_utf8(s).map_err(|_| ()).map(String::from)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   206
    })(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   207
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   208
15571
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   209
fn named_field(input: &[u8]) -> HaskellResult<(String, HaskellValue)> {
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   210
    separated_pair(
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   211
        identifier,
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   212
        delimited(take_while(is_space), tag("="), take_while(is_space)),
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   213
        value,
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   214
    )(input)
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   215
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   216
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   217
fn structure(input: &[u8]) -> HaskellResult<HaskellValue> {
15572
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   218
    alt((
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   219
        map(
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   220
            pair(
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   221
                identifier,
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   222
                surrounded("{", "}", separated_list(comma, named_field)),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   223
            ),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   224
            |(name, mut fields)| HaskellValue::Struct {
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   225
                name,
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   226
                fields: fields.drain(..).collect(),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   227
            },
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   228
        ),
15572
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   229
        map(
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   230
            pair(
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   231
                identifier,
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   232
                preceded(take_while1(is_space), separated_list(comma, value)),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   233
            ),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   234
            |(name, mut fields)| HaskellValue::AnonStruct {
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   235
                name: name.clone(),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   236
                fields,
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   237
            },
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   238
        ),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   239
    ))(input)
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   240
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   241
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   242
fn value(input: &[u8]) -> HaskellResult<HaskellValue> {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   243
    alt((number, string, tuple, list, structure))(input)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   244
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   245
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   246
#[inline]
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   247
pub fn parse(input: &[u8]) -> HaskellResult<HaskellValue> {
15571
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   248
    delimited(take_while(is_space), value, take_while(is_space))(input)
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   249
}
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   250
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   251
mod test {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   252
    use super::*;
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   253
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   254
    #[test]
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   255
    fn terminals() {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   256
        use HaskellValue::*;
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   257
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   258
        matches!(number(b"127"), Ok((_, Number(127))));
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   259
        matches!(number(b"adas"), Err(nom::Err::Error(())));
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   260
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   261
        assert_eq!(
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   262
            string(b"\"Hail \\240\\159\\166\\148!\""),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   263
            Ok((&b""[..], String("Hail \u{1f994}!".to_string())))
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   264
        );
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   265
    }
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   266
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   267
    #[test]
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   268
    fn sequences() {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   269
        use HaskellValue::*;
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   270
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   271
        let value = Tuple(vec![
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   272
            Number(64),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   273
            String("text".to_string()),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   274
            List(vec![Number(1), Number(2), Number(3)]),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   275
        ]);
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   276
15571
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   277
        assert_eq!(tuple(b"(64, \"text\", [1 , 2, 3])"), Ok((&b""[..], value)));
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   278
    }
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   279
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   280
    #[test]
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   281
    fn structures() {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   282
        use HaskellValue::*;
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   283
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   284
        let value = Struct {
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   285
            name: "Hog".to_string(),
15571
ae6b09ae4dcc add whitespace handling
alfadur
parents: 15570
diff changeset
   286
            fields: vec![
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   287
                ("name".to_string(), String("\u{1f994}".to_string())),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   288
                ("health".to_string(), Number(100)),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   289
            ]
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   290
            .drain(..)
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   291
            .collect(),
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   292
        };
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   293
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   294
        assert_eq!(
15572
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   295
            structure(b"Hog {name = \"\\240\\159\\166\\148\", health = 100}"),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   296
            Ok((&b""[..], value))
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   297
        );
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   298
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   299
        let value = AnonStruct {
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   300
            name: "Hog".to_string(),
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   301
            fields: vec![Number(100), String("\u{1f994}".to_string())],
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   302
        };
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   303
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   304
        assert_eq!(
9a333e4e3b50 parse anonymous fields
alfadur
parents: 15571
diff changeset
   305
            structure(b"Hog 100, \"\\240\\159\\166\\148\""),
15570
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   306
            Ok((&b""[..], value))
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   307
        );
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   308
    }
d524b7450576 add haskell literal parser
alfadur
parents:
diff changeset
   309
}