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