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