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