1use std::collections::HashMap;
2use std::fmt::{self, Display, Formatter};
3use regex::Regex;
4
5pub fn stringify(input: &JohnValue) -> String {
6 match input {
7 JohnValue::JohnAbyss => "#".to_string(),
8 JohnValue::JohnBool(b) => b.to_string(),
9 JohnValue::JohnInt(i) => i.to_string(),
10 JohnValue::JohnFloat(f) => f.to_string(),
11 JohnValue::JohnString(s) => format!("\"{}\"", s),
12 JohnValue::JohnChar(c) => format!("'{}'", c),
13 JohnValue::JohnArray(a) => format!("[{}]", a.iter().map(|v| stringify(v)).collect::<Vec<String>>().join(", ")),
14 JohnValue::JohnObject(o) => format!("{{{}}}", o.iter().map(|(k, v)| format!("{}: {}", k, stringify(v))).collect::<Vec<String>>().join(", ")),
15 JohnValue::JohnTuple(t) => format!("({})", t.iter().map(|v| stringify(v)).collect::<Vec<String>>().join(", ")),
16 JohnValue::JohnRange(start, end, step) => {
17 if let Some(step) = step {
18 format!("{}..{}..{}", start, end, step)
19 } else {
20 format!("{}..{}", start, end)
21 }
22 }
23 JohnValue::JohnIndex(true, i) => format!("^{}", i),
24 JohnValue::JohnIndex(false, i) => format!("*{}", i),
25 JohnValue::JohnVersion(major, minor, patch, build) => {
26 if let Some(patch) = patch {
27 if let Some(build) = build {
28 format!("v{}.{}.{}.{}", major, minor, patch, build)
29 } else {
30 format!("v{}.{}.{}", major, minor, patch)
31 }
32 } else {
33 format!("v{}.{}", major, minor)
34 }
35 }
36 }
37}
38
39pub fn parse(input: &str) -> Result<JohnValue, String> {
40 let tokens = tokenize(input);
41 let mut parser = JohnParser::new(tokens);
42 match parser.peek() {
44 Some(Token::Identifier(_)) => {
45 parser.parse_tl_john_object()
46 }
47 Some(_) => {
48 parser.parse_john_value()
49 }
50 None => {
51 Err("Empty input".to_string())
52 }
53 }
54}
55
56struct JohnParser {
57 tokens: Vec<Token>,
58 index: usize,
59}
60
61impl JohnParser {
62 fn new(tokens: Vec<Token>) -> JohnParser {
63 JohnParser {
64 tokens,
65 index: 0,
66 }
67 }
68
69 fn next(&mut self) -> Option<&Token> {
70 if self.index < self.tokens.len() {
71 let token = &self.tokens[self.index];
72 self.index += 1;
73 Some(token)
74 } else {
75 None
76 }
77 }
78
79 fn peek(&self) -> Option<&Token> {
80 if self.index < self.tokens.len() {
81 Some(&self.tokens[self.index])
82 } else {
83 None
84 }
85 }
86
87 fn parse_tl_john_object(&mut self) -> Result<JohnValue, String> {
88 let mut object = HashMap::new();
89 while let Some(Token::Identifier(key)) = self.next() {
90 let k = key.to_string();
91 match self.peek() {
92 Some(_) => {
93 object.insert(k, self.parse_john_value()?);
94 }
95 None => {
96 return Err("Invalid value".to_string())
97 }
98 }
99 }
100 Ok(JohnValue::JohnObject(object))
101 }
102
103 fn parse_john_value(&mut self) -> Result<JohnValue, String> {
104 match self.next() {
105 Some(token) => match token {
106 Token::Value(value) => {
107 parse_john_primitive(value)
108 }
109 Token::OpenCurly => {
110 self.parse_john_object()
111 }
112 Token::OpenSquare => {
113 self.parse_john_array()
114 }
115 Token::OpenParen => {
116 self.parse_john_tuple()
117 }
118 _ => {
119 Err(format!("Unexpected {}", token))
120 }
121 }
122 _ => {
123 Err("Invalid value".to_string())
124 }
125 }
126 }
127
128 fn parse_john_object(&mut self) -> Result<JohnValue, String> {
129 let mut object = HashMap::new();
130 while let Some(Token::Identifier(key)) = self.next() { let k = key.to_string();
132 match self.peek() {
133 Some(_) => {
134 object.insert(k, self.parse_john_value()?);
135 }
136 None => {
137 return Err("Invalid value".to_string())
138 }
139 }
140 }
141 Ok(JohnValue::JohnObject(object))
142 }
143
144 fn parse_john_array(&mut self) -> Result<JohnValue, String> {
145 let mut array = vec![];
146 while let Ok(value) = self.parse_john_value() {
147 array.push(value);
148 }
149 Ok(JohnValue::JohnArray(array))
150 }
152
153 fn parse_john_tuple(&mut self) -> Result<JohnValue, String> {
154 let mut tuple = vec![];
155 while let Ok(value) = self.parse_john_value() {
156 tuple.push(value);
157 }
158 Ok(JohnValue::JohnTuple(tuple))
159 }
160}
161
162fn parse_john_primitive(value: &String) -> Result<JohnValue, String> {
163 if let Ok(int) = value.parse::<i64>() {
164 Ok(JohnValue::JohnInt(int))
165 } else if let Ok(float) = value.parse::<f64>() {
166 Ok(JohnValue::JohnFloat(float))
167 } else if value == "true" {
168 Ok(JohnValue::JohnBool(true))
169 } else if value == "false" {
170 Ok(JohnValue::JohnBool(false))
171 } else if value.starts_with("\"") && value.ends_with("\"") {
172 Ok(JohnValue::JohnString(value[1..value.len() - 1].to_string()))
173 } else if value.starts_with("'") && value.ends_with("'") {
174 Ok(JohnValue::JohnChar(value.chars().nth(1).unwrap()))
175 } else if value == "abyss" || value == "#" {
176 Ok(JohnValue::JohnAbyss)
177 } else if value.starts_with("v") {
178 let parts: Vec<&str> = value[1..].split('.').collect();
179 let major = parts[0].parse::<i64>().unwrap();
180 let minor = parts[1].parse::<i64>().unwrap();
181 if parts.len() == 2 {
182 Ok(JohnValue::JohnVersion(major, minor, None, None))
183 } else if parts.len() == 3 {
184 Ok(JohnValue::JohnVersion(major, minor, Some(parts[2].parse::<i64>().unwrap()), None))
185 } else if parts.len() == 4 {
186 Ok(JohnValue::JohnVersion(major, minor, Some(parts[2].parse::<i64>().unwrap()), Some(parts[3].parse::<i64>().unwrap())))
187 } else {
188 Err("Invalid version".to_string())
189 }
190 } else if value.starts_with("*") {
191 Ok(JohnValue::JohnIndex(false, value[1..].parse::<i64>().unwrap()))
192 } else if value.starts_with("^") {
193 Ok(JohnValue::JohnIndex(true, value[1..].parse::<i64>().unwrap()))
194 } else if value.contains("..") {
195 let parts: Vec<&str> = value.split("..").collect();
196 let start = parts[0].parse::<i64>().unwrap();
197 let end = parts[1].parse::<i64>().unwrap();
198 if parts.len() == 2 {
199 Ok(JohnValue::JohnRange(start, end, None))
200 } else if parts.len() == 3 {
201 Ok(JohnValue::JohnRange(start, end, Some(parts[2].parse::<i64>().unwrap())))
202 } else {
203 Err("Invalid range".to_string())
204 }
205 } else {
206 Err("Invalid value".to_string())
207 }
208}
209
210pub fn minify(input: &str) -> String {
211 let re = Regex::new(r"\s*([\{\[\(\)\]\}])\s*").unwrap();
212 let tokens = tokenize(input);
213 return re.replace_all(
214 &tokens
215 .iter()
216 .map(|t| t.into())
217 .collect::<Vec<String>>()
218 .join(" "),
219 "$1"
220 ).into();
221}
222
223fn tokenize(input: &str) -> Vec<Token> {
224 let mut tokens = vec![];
225 let mut chars = input.chars().peekable();
226 while let Some(c) = chars.next() {
227 match c {
228 '{' => tokens.push(Token::OpenCurly),
229 '}' => tokens.push(Token::CloseCurly),
230 '[' => tokens.push(Token::OpenSquare),
231 ']' => tokens.push(Token::CloseSquare),
232 '(' => tokens.push(Token::OpenParen),
233 ')' => tokens.push(Token::CloseParen),
234 _ if c.is_whitespace() || c == ':' || c == ',' || c == ';' => {}
235 _ => {
237 let mut s = String::new();
238 s.push(c);
239 while let Some(&c) = chars.peek() {
240 if !c.is_whitespace() && c != ':' && c != ',' && c != ';' && c != '{' && c != '}' && c != '[' && c != ']' && c != '(' && c != ')' {
241 s.push(c);
242 chars.next();
243 } else {
244 break;
245 }
246 }
247 tokens.push(s.into());
248 }
249 }
250 }
251 tokens
252}
253
254#[derive(Debug)]
255#[derive(PartialEq)]
256enum Token {
257 OpenCurly,
258 CloseCurly,
259 OpenSquare,
260 CloseSquare,
261 OpenParen,
262 CloseParen,
263 Value(String),
264 Identifier(String)
265}
266
267impl Into<String> for &Token {
268 fn into(self) -> String {
269 match self {
270 Token::OpenCurly => "{".to_string(),
271 Token::CloseCurly => "}".to_string(),
272 Token::OpenSquare => "[".to_string(),
273 Token::CloseSquare => "]".to_string(),
274 Token::OpenParen => "(".to_string(),
275 Token::CloseParen => ")".to_string(),
276 Token::Value(s) => s.to_string(),
277 Token::Identifier(s) => s.to_string(),
278 }
279 }
280}
281
282impl Display for Token {
283 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
284 write!(f, "{}", Into::<String>::into(self))
285 }
286}
287
288impl From<String> for Token {
289 fn from(s: String) -> Self {
290 match s.as_str() {
291 "{" => Token::OpenCurly,
292 "}" => Token::CloseCurly,
293 "[" => Token::OpenSquare,
294 "]" => Token::CloseSquare,
295 "(" => Token::OpenParen,
296 ")" => Token::CloseParen,
297 _ => {
298 let re = Regex::new(r"^[a-zA-Z_]\w*$").unwrap();
300 if re.is_match(&s) && s != "true" && s != "false" && s != "abyss" {
301 Token::Identifier(s)
302 } else {
303 Token::Value(s)
304 }
305 }
306 }
307 }
308}
309
310#[derive(Debug)]
311#[derive(PartialEq)]
312pub enum JohnValue {
313 JohnAbyss,
314 JohnBool(bool),
315 JohnInt(i64),
316 JohnFloat(f64),
317 JohnString(String),
318 JohnChar(char),
319 JohnArray(Vec<JohnValue>),
320 JohnObject(HashMap<String, JohnValue>),
321 JohnTuple(Vec<JohnValue>),
322 JohnRange(i64, i64, Option<i64>),
323 JohnIndex(bool, i64),
324 JohnVersion(i64, i64, Option<i64>, Option<i64>),
325}
326
327#[cfg(test)]
328mod tests {
329 use super::*;
330
331 #[test]
332 fn test_tokenize() {
333 assert_eq!(tokenize(r#"
334 {
335 a: 1,
336 b 2;
337 c [
338 3,
339 4
340 { d: "hi" }
341 ], g (1 "2" 3)
342 }
343 "#), vec![
344 Token::OpenCurly,
345 Token::Identifier("a".to_string()),
346 Token::Value("1".to_string()),
347 Token::Identifier("b".to_string()),
348 Token::Value("2".to_string()),
349 Token::Identifier("c".to_string()),
350 Token::OpenSquare,
351 Token::Value("3".to_string()),
352 Token::Value("4".to_string()),
353 Token::OpenCurly,
354 Token::Identifier("d".to_string()),
355 Token::Value("\"hi\"".to_string()),
356 Token::CloseCurly,
357 Token::CloseSquare,
358 Token::Identifier("g".to_string()),
359 Token::OpenParen,
360 Token::Value("1".to_string()),
361 Token::Value("\"2\"".to_string()),
362 Token::Value("3".to_string()),
363 Token::CloseParen,
364 Token::CloseCurly,
365 ]);
366 }
367
368 #[test]
369 fn test_minify() {
370 assert_eq!(minify(r"
371 {
372 a: 1,
373 b 2;
374 c 3
375 }
376 "), r"{a 1 b 2 c 3}");
377 }
378
379 #[test]
380 fn test_value_int() {
381 assert_eq!(parse("1"), Ok(JohnValue::JohnInt(1)));
382 }
383
384 #[test]
385 fn test_value_float() {
386 assert_eq!(parse("1.25"), Ok(JohnValue::JohnFloat(1.25)));
387 }
388
389 #[test]
390 fn test_value_string() {
391 assert_eq!(parse(r#""hello""#), Ok(JohnValue::JohnString("hello".to_string())));
392 }
393
394 #[test]
395 fn test_value_char() {
396 assert_eq!(parse("'a'"), Ok(JohnValue::JohnChar('a')));
397 }
398
399 #[test]
400 fn test_value_bool() {
401 assert_eq!(parse("true"), Ok(JohnValue::JohnBool(true)));
402 assert_eq!(parse("false"), Ok(JohnValue::JohnBool(false)));
403 }
404
405 #[test]
406 fn test_value_abyss() {
407 assert_eq!(parse("#"), Ok(JohnValue::JohnAbyss));
408 assert_eq!(parse("abyss"), Ok(JohnValue::JohnAbyss));
409 }
410
411 #[test]
412 fn test_value_range() {
413 assert_eq!(parse("1..5"), Ok(JohnValue::JohnRange(1, 5, None)));
414 assert_eq!(parse("1..5..2"), Ok(JohnValue::JohnRange(1, 5, Some(2))));
415 }
416
417 #[test]
418 fn test_value_index() {
419 assert_eq!(parse("*1"), Ok(JohnValue::JohnIndex(false, 1)));
420 assert_eq!(parse("^1"), Ok(JohnValue::JohnIndex(true, 1)));
421 }
422
423 #[test]
424 fn test_value_version() {
425 assert_eq!(parse("v1.2"), Ok(JohnValue::JohnVersion(1, 2, None, None)));
426 assert_eq!(parse("v1.2.3"), Ok(JohnValue::JohnVersion(1, 2, Some(3), None)));
427 assert_eq!(parse("v1.2.3.4"), Ok(JohnValue::JohnVersion(1, 2, Some(3), Some(4))));
428 }
429
430 #[test]
431 fn test_tl_object() {
432 assert_eq!(parse("a 1 b 2 c 3"), Ok(JohnValue::JohnObject(
433 vec![
434 ("a".to_string(), JohnValue::JohnInt(1)),
435 ("b".to_string(), JohnValue::JohnInt(2)),
436 ("c".to_string(), JohnValue::JohnInt(3)),
437 ].into_iter().collect()
438 )));
439 }
440
441 #[test]
442 fn test_value_array() {
443 assert_eq!(parse("[1, 2, 3]"), Ok(JohnValue::JohnArray(
444 vec![
445 JohnValue::JohnInt(1),
446 JohnValue::JohnInt(2),
447 JohnValue::JohnInt(3),
448 ]
449 )));
450 }
451
452 #[test]
453 fn test_value_tuple() {
454 assert_eq!(parse("(1, 2, 3)"), Ok(JohnValue::JohnTuple(
455 vec![
456 JohnValue::JohnInt(1),
457 JohnValue::JohnInt(2),
458 JohnValue::JohnInt(3),
459 ]
460 )));
461 }
462
463 #[test]
464 fn test_value_tuple_different_types() {
465 assert_eq!(parse(r#"(1, "2", 3.0)"#), Ok(JohnValue::JohnTuple(
466 vec![
467 JohnValue::JohnInt(1),
468 JohnValue::JohnString("2".to_string()),
469 JohnValue::JohnFloat(3.0),
470 ]
471 )));
472 }
473
474 #[test]
475 fn test_value_object() {
476 assert_eq!(parse(r#"
477 {
478 a: 1,
479 b 2;
480 c 3
481 }
482 "#), Ok(JohnValue::JohnObject(
483 vec![
484 ("a".to_string(), JohnValue::JohnInt(1)),
485 ("b".to_string(), JohnValue::JohnInt(2)),
486 ("c".to_string(), JohnValue::JohnInt(3)),
487 ].into_iter().collect()
488 )));
489 }
490
491 #[test]
492 fn test_value_object_nested() {
493 assert_eq!(parse(r#"
494 {
495 a: 1,
496 b 2;
497 c [
498 3,
499 4
500 { d: "hi" }
501 ], g (1 "2" 3)
502 }
503 "#), Ok(JohnValue::JohnObject(
504 vec![
505 ("a".to_string(), JohnValue::JohnInt(1)),
506 ("b".to_string(), JohnValue::JohnInt(2)),
507 ("c".to_string(), JohnValue::JohnArray(
508 vec![
509 JohnValue::JohnInt(3),
510 JohnValue::JohnInt(4),
511 JohnValue::JohnObject(
512 vec![
513 ("d".to_string(), JohnValue::JohnString("hi".to_string())),
514 ].into_iter().collect()
515 ),
516 ]
517 )),
518 ("g".to_string(), JohnValue::JohnTuple(
519 vec![
520 JohnValue::JohnInt(1),
521 JohnValue::JohnString("2".to_string()),
522 JohnValue::JohnInt(3),
523 ]
524 )),
525 ].into_iter().collect()
526 )));
527 }
528
529 #[test]
530 fn test_value_object_nested_nested() {
531 assert_eq!(parse(r#"
532 {
533 a: 1,
534 b 2;
535 c [
536 3,
537 4
538 { d: "hi" }
539 ], g (1 "2" 3),
540 h {
541 i: 5,
542 j 6
543 }
544 }
545 "#), Ok(JohnValue::JohnObject(
546 vec![
547 ("a".to_string(), JohnValue::JohnInt(1)),
548 ("b".to_string(), JohnValue::JohnInt(2)),
549 ("c".to_string(), JohnValue::JohnArray(
550 vec![
551 JohnValue::JohnInt(3),
552 JohnValue::JohnInt(4),
553 JohnValue::JohnObject(
554 vec![
555 ("d".to_string(), JohnValue::JohnString("hi".to_string())),
556 ].into_iter().collect()
557 ),
558 ]
559 )),
560 ("g".to_string(), JohnValue::JohnTuple(
561 vec![
562 JohnValue::JohnInt(1),
563 JohnValue::JohnString("2".to_string()),
564 JohnValue::JohnInt(3),
565 ]
566 )),
567 ("h".to_string(), JohnValue::JohnObject(
568 vec![
569 ("i".to_string(), JohnValue::JohnInt(5)),
570 ("j".to_string(), JohnValue::JohnInt(6)),
571 ].into_iter().collect()
572 )),
573 ].into_iter().collect()
574 )));
575 }
576
577 #[test]
578 fn test_stringify() {
579 assert_eq!(stringify(&JohnValue::JohnInt(1)), "1".to_string());
580 assert_eq!(stringify(&JohnValue::JohnFloat(1.25)), "1.25".to_string());
581 assert_eq!(stringify(&JohnValue::JohnString("hello".to_string())), r#""hello""#.to_string());
582 assert_eq!(stringify(&JohnValue::JohnChar('a')), r#"'a'"#.to_string());
583 assert_eq!(stringify(&JohnValue::JohnBool(true)), "true".to_string());
584 assert_eq!(stringify(&JohnValue::JohnBool(false)), "false".to_string());
585 assert_eq!(stringify(&JohnValue::JohnAbyss), "#".to_string());
586 assert_eq!(stringify(&JohnValue::JohnRange(1, 5, None)), "1..5".to_string());
587 assert_eq!(stringify(&JohnValue::JohnRange(1, 5, Some(2))), "1..5..2".to_string());
588 assert_eq!(stringify(&JohnValue::JohnIndex(false, 1)), "*1".to_string());
589 assert_eq!(stringify(&JohnValue::JohnIndex(true, 1)), "^1".to_string());
590 assert_eq!(stringify(&JohnValue::JohnVersion(1, 2, None, None)), "v1.2".to_string());
591 assert_eq!(stringify(&JohnValue::JohnVersion(1, 2, Some(3), None)), "v1.2.3".to_string());
592 assert_eq!(stringify(&JohnValue::JohnVersion(1, 2, Some(3), Some(4)),), "v1.2.3.4".to_string());
593 assert_eq!(stringify(&JohnValue::JohnArray(
594 vec![
595 JohnValue::JohnInt(1),
596 JohnValue::JohnInt(2),
597 JohnValue::JohnInt(3),
598 ]
599 )), "[1, 2, 3]".to_string());
600 assert_eq!(stringify(&JohnValue::JohnTuple(
601 vec![
602 JohnValue::JohnInt(1),
603 JohnValue::JohnInt(2),
604 JohnValue::JohnInt(3),
605 ]
606 )), "(1, 2, 3)".to_string());
607 }
608}