1use std::collections::HashSet;
2#[cfg(feature = "file")]
3use std::fs::File;
4#[cfg(feature = "file")]
5use std::io::Read;
6use std::sync::Arc;
7
8use range::Range;
9use read_token::{NumberSettings, ReadToken};
10
11#[cfg(feature = "file")]
12use super::io::io_error;
13
14use crate::Variable;
15
16type Strings = HashSet<Arc<String>>;
17
18#[cfg(feature = "file")]
20pub fn load_file(file: &str) -> Result<Variable, String> {
21 let mut data_file = File::open(file).map_err(|err| io_error("open", file, &err))?;
22 let mut d = String::new();
23 data_file
24 .read_to_string(&mut d)
25 .map_err(|err| io_error("read", file, &err))?;
26 load_data(&d)
27}
28
29#[cfg(not(feature = "file"))]
30pub fn load_file(_: &str) -> Result<Variable, String> {
31 Err(super::FILE_SUPPORT_DISABLED.into())
32}
33
34pub fn load_data(data: &str) -> Result<Variable, String> {
36 let mut read = ReadToken::new(data, 0);
37 let mut strings: Strings = HashSet::new();
38 opt_w(&mut read);
39 expr(&mut read, &mut strings, data)
40}
41
42static NUMBER_SETTINGS: NumberSettings = NumberSettings {
43 allow_underscore: true,
44};
45
46const SEPS: &str = "(){}[],.:;\n\"\\";
47
48fn expr(read: &mut ReadToken, strings: &mut Strings, data: &str) -> Result<Variable, String> {
49 if let Some(range) = read.tag("{") {
50 *read = read.consume(range.length);
52 return object(read, strings, data);
53 }
54 if let Some(range) = read.tag("[") {
55 *read = read.consume(range.length);
57 return array(read, strings, data);
58 }
59 if let Some(range) = read.tag("(") {
60 *read = read.consume(range.length);
62 return vec4(read, data);
63 }
64 if let Some(range) = read.tag("#") {
65 use read_color::rgb_maybe_a;
66
67 *read = read.consume(range.length);
69 let (range, _) = read.until_any_or_whitespace(SEPS);
70 let val = read.raw_string(range.length);
71 if let Some((rgb, a)) = rgb_maybe_a(&mut val.chars()) {
72 let v = [
73 f32::from(rgb[0]) / 255.0,
74 f32::from(rgb[1]) / 255.0,
75 f32::from(rgb[2]) / 255.0,
76 f32::from(a.unwrap_or(255)) / 255.0,
77 ];
78 return Ok(Variable::Vec4(v));
79 } else {
80 return Err(error(
81 range,
82 "Expected hex color in format `FFFFFF`or `FFFFFFFF`",
83 data,
84 ));
85 }
86 }
87 if let Some(range) = read.tag("link") {
88 *read = read.consume(range.length);
90 return link(read, strings, data);
91 }
92 if let Some(range) = read.string() {
94 match read.parse_string(range.length) {
95 Ok(s) => {
96 *read = read.consume(range.length);
97 return Ok(Variable::Str(if let Some(s) = strings.get(&s) {
98 s.clone()
99 } else {
100 Arc::new(s)
101 }));
102 }
103 Err(err_range) => {
104 let (range, err) = err_range.decouple();
105 return Err(error(range, &format!("{}", err), data));
106 }
107 }
108 }
109 if let Some(range) = read.number(&NUMBER_SETTINGS) {
111 match read.parse_number(&NUMBER_SETTINGS, range.length) {
112 Ok(val) => {
113 *read = read.consume(range.length);
114 return Ok(Variable::f64(val));
115 }
116 Err(err) => return Err(error(range, &format!("{}", err), data)),
117 }
118 }
119 if let Some(range) = read.tag("false") {
121 *read = read.consume(range.length);
122 return Ok(Variable::bool(false));
123 }
124 if let Some(range) = read.tag("true") {
125 *read = read.consume(range.length);
126 return Ok(Variable::bool(true));
127 }
128 if let Some(range) = read.tag("none()") {
130 *read = read.consume(range.length);
131 return Ok(Variable::Option(None));
132 }
133 if let Some(range) = read.tag("some(") {
134 *read = read.consume(range.length);
135 opt_w(read);
136 let res = expr(read, strings, data)?;
137 opt_w(read);
138 return if let Some(range) = read.tag(")") {
139 *read = read.consume(range.length);
140 Ok(Variable::Option(Some(Box::new(res))))
141 } else {
142 Err(error(read.start(), "Expected `)`", data))
143 };
144 }
145 Err(error(read.start(), "Reached end of file", data))
146}
147
148fn object(read: &mut ReadToken, strings: &mut Strings, data: &str) -> Result<Variable, String> {
149 use std::collections::HashMap;
150
151 let mut res: HashMap<Arc<String>, Variable> = HashMap::new();
152 let mut was_comma = false;
153 loop {
154 opt_w(read);
155
156 if let Some(range) = read.tag("}") {
157 *read = read.consume(range.length);
158 break;
159 }
160
161 if !res.is_empty() && !was_comma {
162 return Err(error(read.start(), "Expected `,`", data));
163 }
164
165 let key: Arc<String>;
166 if let Some(range) = read.string() {
167 match read.parse_string(range.length) {
168 Ok(s) => {
169 key = if let Some(s) = strings.get(&s) {
171 s.clone()
172 } else {
173 Arc::new(s)
174 };
175 *read = read.consume(range.length);
176 }
177 Err(err_range) => {
178 let (range, err) = err_range.decouple();
179 return Err(error(range, &format!("{}", err), data));
180 }
181 }
182 } else {
183 let (range, _) = read.until_any_or_whitespace(SEPS);
184 if range.length == 0 {
185 return Err(error(range, "Expected key", data));
186 } else {
187 let k = read.raw_string(range.length);
188 key = if let Some(s) = strings.get(&k) {
190 s.clone()
191 } else {
192 Arc::new(k)
193 };
194 *read = read.consume(range.length);
195 };
196 }
197
198 opt_w(read);
199
200 if let Some(range) = read.tag(":") {
201 *read = read.consume(range.length);
202 } else {
203 return Err(error(read.start(), "Expected `:`", data));
204 }
205
206 opt_w(read);
207
208 res.insert(key, expr(read, strings, data)?);
209
210 was_comma = comma(read);
211 }
212 Ok(Variable::Object(Arc::new(res)))
213}
214
215fn array(read: &mut ReadToken, strings: &mut Strings, data: &str) -> Result<Variable, String> {
216 let mut res = vec![];
217 let mut was_comma = false;
218 loop {
219 opt_w(read);
220
221 if let Some(range) = read.tag("]") {
222 *read = read.consume(range.length);
223 break;
224 }
225
226 if !res.is_empty() && !was_comma {
227 return Err(error(read.start(), "Expected `,`", data));
228 }
229
230 res.push(expr(read, strings, data)?);
231 was_comma = comma(read);
232 }
233 Ok(Variable::Array(Arc::new(res)))
234}
235
236fn link(read: &mut ReadToken, strings: &mut Strings, data: &str) -> Result<Variable, String> {
237 use crate::Link;
238
239 opt_w(read);
240
241 if let Some(range) = read.tag("{") {
242 *read = read.consume(range.length);
243 } else {
244 return Err(error(read.start(), "Expected `{`", data));
245 }
246
247 let mut link = Link::new();
248
249 opt_w(read);
250
251 loop {
252 opt_w(read);
253
254 if let Some(range) = read.tag("}") {
255 *read = read.consume(range.length);
256 break;
257 }
258
259 match link.push(&expr(read, strings, data)?) {
260 Ok(()) => {}
261 Err(err) => return Err(err),
262 };
263 }
264 Ok(Variable::Link(Box::new(link)))
265}
266
267fn vec4(read: &mut ReadToken, data: &str) -> Result<Variable, String> {
268 let x = if let Some(range) = read.number(&NUMBER_SETTINGS) {
269 match read.parse_number(&NUMBER_SETTINGS, range.length) {
270 Ok(x) => {
271 *read = read.consume(range.length);
272 x
273 }
274 Err(err) => return Err(error(range, &format!("{}", err), data)),
275 }
276 } else {
277 return Err(error(read.start(), "Expected x component", data));
278 };
279 comma(read);
280 let y = if let Some(range) = read.number(&NUMBER_SETTINGS) {
281 match read.parse_number(&NUMBER_SETTINGS, range.length) {
282 Ok(y) => {
283 *read = read.consume(range.length);
284 y
285 }
286 Err(err) => return Err(error(range, &format!("{}", err), data)),
287 }
288 } else {
289 return Err(error(read.start(), "Expected y component", data));
290 };
291 let (z, w) = if comma(read) {
292 if let Some(range) = read.number(&NUMBER_SETTINGS) {
293 match read.parse_number(&NUMBER_SETTINGS, range.length) {
294 Ok(z) => {
295 *read = read.consume(range.length);
296 comma(read);
297 if let Some(range) = read.number(&NUMBER_SETTINGS) {
298 match read.parse_number(&NUMBER_SETTINGS, range.length) {
299 Ok(w) => {
300 *read = read.consume(range.length);
301 (z, w)
302 }
303 Err(err) => return Err(error(range, &format!("{}", err), data)),
304 }
305 } else {
306 (z, 0.0)
307 }
308 }
309 Err(err) => return Err(error(range, &format!("{}", err), data)),
310 }
311 } else {
312 (0.0, 0.0)
313 }
314 } else {
315 (0.0, 0.0)
316 };
317 opt_w(read);
318 if let Some(range) = read.tag(")") {
319 *read = read.consume(range.length);
320 } else {
321 return Err(error(read.start(), "Expected `)`", data));
322 }
323 Ok(Variable::Vec4([x as f32, y as f32, z as f32, w as f32]))
324}
325
326fn opt_w(read: &mut ReadToken) {
328 loop {
329 let start = *read;
330 let range = read.whitespace();
331 *read = read.consume(range.length);
332
333 if let Some(range) = read.tag("//") {
335 *read = read.consume(range.length);
336 let (range, _) = read.until_any("\n");
337 *read = read.consume(range.length);
338 }
339
340 multi_line_comment(read);
341
342 if read.subtract(&start).length == 0 {
343 break;
344 }
345 }
346}
347
348fn multi_line_comment(read: &mut ReadToken) {
349 if let Some(range) = read.tag("/*") {
351 *read = read.consume(range.length);
352 let (range, _) = read.until_any("*/");
353 *read = read.consume(range.length);
354 loop {
355 let start = *read;
356
357 if read.tag("*/").is_none() {
358 if let Some(range) = read.tag("*") {
359 *read = read.consume(range.length);
360 let (range, _) = read.until_any("*/");
361 *read = read.consume(range.length);
362 }
363 }
364
365 let start_multi_line = *read;
366 multi_line_comment(read);
367 if read.subtract(&start_multi_line).length > 0 {
368 let (range, _) = read.until_any("*/");
369 *read = read.consume(range.length);
370 } else {
371 *read = start_multi_line;
372 if let Some(range) = read.tag("/") {
373 *read = read.consume(range.length);
374 let (range, _) = read.until_any("*/");
375 *read = read.consume(range.length);
376 }
377 }
378
379 if read.subtract(&start).length == 0 {
380 break;
381 }
382 }
383
384 if let Some(range) = read.tag("*/") {
385 *read = read.consume(range.length);
386 }
387 }
388}
389
390fn comma(read: &mut ReadToken) -> bool {
392 let mut res = false;
393 opt_w(read);
394 if let Some(range) = read.tag(",") {
395 *read = read.consume(range.length);
396 res = true;
397 }
398 opt_w(read);
399 res
400}
401
402fn error(range: Range, msg: &str, data: &str) -> String {
404 use piston_meta::ParseErrorHandler;
405
406 let mut handler = ParseErrorHandler::new(data);
407 let mut buf: Vec<u8> = vec![];
408 handler.write_msg(&mut buf, range, msg).unwrap();
409 String::from_utf8(buf).unwrap()
410}