1use crate::span::{Position, Span, Spanned};
6use crate::error::{RonErrorKind, RonParseError};
7use super::{RonValue, RonStruct};
8
9#[derive(Debug)]
10struct Parser<'a> {
11 source: &'a str,
12 bytes: &'a [u8],
13 offset: usize,
14 line: usize,
15 column: usize,
16}
17
18impl<'a> Parser<'a> {
19 fn new(source: &'a str) -> Self {
20 Self { source, bytes: source.as_bytes(), offset: 0, line: 1, column: 1 }
21 }
22
23 fn position(&self) -> Position {
24 Position { offset: self.offset, line: self.line, column: self.column }
25 }
26
27 fn peek(&self) -> Option<u8> {
28 self.bytes.get(self.offset).copied()
29 }
30
31 fn advance(&mut self) {
32 if let Some(byte) = self.peek() {
33 if byte == b'\n'{
34 self.column = 1;
35 self.line += 1;
36 } else {
37 self.column += 1;
38 }
39 self.offset += 1;
40 }
41 }
42
43 fn skip_whitespace(&mut self) {
44 loop {
45 match self.peek() {
46 Some(b' ' | b'\t' | b'\n' | b'\r') => self.advance(),
47 Some(b'/') if self.bytes.get(self.offset + 1) == Some(&b'/') => {
48 while self.peek().is_some_and(|b| b != b'\n') {
49 self.advance();
50 }
51 }
52 _ => break,
53 }
54 }
55 }
56
57 fn expect_char(&mut self, expected: u8) -> Result<(), RonParseError> {
58 let start = self.position();
59 match self.peek() {
60 Some(b) if b == expected => {
61 self.advance();
62 Ok(())
63 },
64 Some(b) => {
65 self.advance();
66 let end = self.position();
67 Err(RonParseError {
68 span: Span {
69 start,
70 end
71 },
72 kind: RonErrorKind::UnexpectedToken {
73 expected: format!("'{}'", expected as char),
74 found: format!("'{}'", b as char)
75 }
76 })
77 },
78 None => {
79 Err(RonParseError {
80 span: Span {
81 start,
82 end: start
83 },
84 kind: RonErrorKind::UnexpectedToken {
85 expected: format!("'{}'", expected as char),
86 found: "end of input".to_string()
87 }
88 })
89 }
90 }
91 }
92
93 fn parse_identifier(&mut self) -> Result<Spanned<String>, RonParseError> {
94 let start = self.position();
95
96 match self.peek() {
98 Some(b) if b.is_ascii_alphabetic() || b == b'_' => {},
99 Some(b) => {
100 self.advance();
101 let end = self.position();
102 return Err(RonParseError {
103 span: Span { start, end },
104 kind: RonErrorKind::UnexpectedToken {
105 expected: "identifier".to_string(),
106 found: format!("'{}'", b as char),
107 },
108 });
109 },
110 None => {
111 return Err(RonParseError {
112 span: Span { start, end: start },
113 kind: RonErrorKind::UnexpectedToken {
114 expected: "identifier".to_string(),
115 found: "end of input".to_string(),
116 },
117 });
118 },
119 }
120
121 while self.peek().is_some_and(|b| b.is_ascii_alphanumeric() || b == b'_') {
123 self.advance();
124 }
125
126 let end = self.position();
128 Ok(Spanned {
129 value: self.source[start.offset..end.offset].to_string(),
130 span: Span { start, end },
131 })
132 }
133
134 #[allow(clippy::too_many_lines)]
135 fn parse_value(&mut self) -> Result<Spanned<RonValue>, RonParseError> {
136 self.skip_whitespace();
137 let start = self.position();
138
139 match self.peek() {
140 Some(b'"') => {
141 self.advance(); let mut content = String::new();
143 loop {
144 match self.peek() {
145 Some(b'"') => {
146 self.advance(); break;
148 }
149 Some(b'\\') => {
153 self.advance(); match self.peek() {
155 Some(b'n') => { content.push('\n'); self.advance(); }
156 Some(b't') => { content.push('\t'); self.advance(); }
157 Some(b'\\') => { content.push('\\'); self.advance(); }
158 Some(b'"') => { content.push('"'); self.advance(); }
159 Some(b) => { content.push(b as char); self.advance(); }
160 None => {
161 return Err(RonParseError {
162 span: Span { start, end: self.position() },
163 kind: RonErrorKind::UnterminatedString,
164 });
165 }
166 }
167 }
168 Some(b) => {
169 content.push(b as char);
170 self.advance();
171 }
172 None => {
173 return Err(RonParseError {
174 span: Span { start, end: self.position() },
175 kind: RonErrorKind::UnterminatedString,
176 });
177 }
178 }
179 }
180 let end = self.position();
181 Ok(Spanned {
182 value: RonValue::String(content),
183 span: Span { start, end },
184 })
185 },
186 Some(b) if b.is_ascii_digit() || b == b'-' => {
187 if b == b'-' {
188 self.advance();
189 }
190
191 let mut has_dot = false;
192
193 loop {
194 match self.peek() {
195 Some(b) if b.is_ascii_digit() => {self.advance();},
196 Some(b'.') if !has_dot => {
197 has_dot = true;
198 self.advance();
199 },
200 Some(_) | None => {break;}
201 }
202 }
203
204 let end = self.position();
205 let number_str = &self.source[start.offset..end.offset];
206 if has_dot {
207 let num_float = number_str.parse::<f64>();
208 if let Ok(num) = num_float {
209 Ok(Spanned {
210 value: RonValue::Float(num),
211 span: Span { start, end },
212 })
213 } else {
214 Err(RonParseError {
215 span: Span { start, end },
216 kind: RonErrorKind::InvalidNumber { text: number_str.to_string() }
217 })
218 }
219 } else {
220 let num_int = number_str.parse::<i64>();
221 if let Ok(num) = num_int {
222 Ok(Spanned {
223 value: RonValue::Integer(num),
224 span: Span { start, end },
225 })
226 } else {
227 Err(RonParseError {
228 span: Span { start, end },
229 kind: RonErrorKind::InvalidNumber { text: number_str.to_string() }
230 })
231 }
232 }
233 },
234 Some(b) if b.is_ascii_alphabetic() => {
235 let identifier = self.parse_identifier()?;
236 let word = identifier.value.as_str();
237 let identifier_span = identifier.span;
238 match word {
239 "true" => {
240 Ok(Spanned { value: RonValue::Bool(true), span: identifier_span })
241 },
242 "false" => {
243 Ok(Spanned { value: RonValue::Bool(false), span: identifier_span })
244 }
245 "None" => {
246 Ok(Spanned { value: RonValue::Option(None), span: identifier_span })
247 }
248 "Some" => {
249 self.skip_whitespace();
250 self.expect_char(b'(')?;
251 let inner = self.parse_value()?;
252 self.expect_char(b')')?;
253 Ok(Spanned {
254 value: RonValue::Option(Some(Box::new(inner))),
255 span: Span { start, end: self.position() }
256 })
257 }
258 _ => {
259 Ok(Spanned {
260 value: RonValue::Identifier(word.to_string()),
261 span: identifier_span
262 })
263 }
264 }
265 },
266 Some(b'[') => {
267 self.advance();
268 let mut elements = Vec::new();
269 loop {
270 self.skip_whitespace();
271 if let Some(b']') = self.peek() {
272 break;
273 }
274 let value = self.parse_value()?;
275 elements.push(value);
276 self.skip_whitespace();
277 if let Some(b',') = self.peek() {
278 self.advance();
279 }
280 }
281 self.expect_char(b']')?;
282 Ok(Spanned {
283 value: RonValue::List(elements),
284 span: Span { start, end: self.position() }
285 })
286 },
287 Some(b'{') => {
288 self.advance();
289 let mut entries: Vec<(Spanned<RonValue>, Spanned<RonValue>)> = Vec::new();
290 loop {
291 self.skip_whitespace();
292 if let Some(b'}') = self.peek() {
293 break;
294 }
295 let key = self.parse_value()?;
296 self.skip_whitespace();
297 self.expect_char(b':')?;
298 self.skip_whitespace();
299 let value = self.parse_value()?;
300 entries.push((key, value));
301 self.skip_whitespace();
302 if let Some(b',') = self.peek() {
303 self.advance();
304 }
305 }
306 self.expect_char(b'}')?;
307 Ok(Spanned {
308 value: RonValue::Map(entries),
309 span: Span { start, end: self.position() },
310 })
311 },
312 Some(b'(') => {
313 self.advance();
314 let mut fields: Vec<(Spanned<String>, Spanned<RonValue>)> = Vec::new();
315 loop {
316 self.skip_whitespace();
317 if let Some(b')') = self.peek() {
318 break;
319 }
320 let field = self.parse_identifier()?;
321 self.skip_whitespace();
322 self.expect_char(b':')?;
323 self.skip_whitespace();
324 let value = self.parse_value()?;
325 fields.push((field, value));
326 self.skip_whitespace();
327 match self.peek() {
328 Some(b',') => self.advance(),
329 Some(_) => {}
330 None => {
331 return Err(RonParseError {
332 span: Span { start, end: self.position() } ,
333 kind: RonErrorKind::UnexpectedToken {
334 expected: "character".to_string(),
335 found: "end of file".to_string() }
336 });
337 }
338 }
339 }
340 let close_span_start = self.position();
341 self.expect_char(b')')?;
342 let close_span = Span{ start: close_span_start, end: self.position() };
343 Ok(Spanned {
344 value: RonValue::Struct(RonStruct { fields, close_span }),
345 span: Span { start, end: self.position() }
346 })
347 }
348 Some(b) => {
349 self.advance();
350 let end = self.position();
351 Err(RonParseError {
352 span: Span { start, end },
353 kind: RonErrorKind::UnexpectedToken {
354 expected: "value".to_string(),
355 found: format!("{}", b as char)
356 }
357 })
358 },
359 None => {
360 Err(RonParseError {
361 span: Span { start, end: start },
362 kind: RonErrorKind::UnexpectedToken {
363 expected: "value".to_string(),
364 found: "end of file".to_string()
365 }
366 })
367 }
368 }
369 }
370}
371
372pub fn parse_ron(source: &str) -> Result<Spanned<RonValue>, RonParseError> {
378 let mut parser = Parser::new(source);
379 parser.parse_value()
380}
381
382#[cfg(test)]
383mod tests {
384 use super::*;
385
386 fn parser(source: &str) -> Parser<'_> {
387 Parser::new(source)
388 }
389
390 #[test]
396 fn string_simple() {
397 let mut p = parser("\"hello\"");
398 let v = p.parse_value().unwrap();
399 assert_eq!(v.value, RonValue::String("hello".to_string()));
400 }
401
402 #[test]
404 fn string_empty() {
405 let mut p = parser("\"\"");
406 let v = p.parse_value().unwrap();
407 assert_eq!(v.value, RonValue::String("".to_string()));
408 }
409
410 #[test]
412 fn string_with_spaces() {
413 let mut p = parser("\"Ashborn Hound\"");
414 let v = p.parse_value().unwrap();
415 assert_eq!(v.value, RonValue::String("Ashborn Hound".to_string()));
416 }
417
418 #[test]
420 fn string_escaped_quote() {
421 let mut p = parser("\"say \\\"hi\\\"\"");
422 let v = p.parse_value().unwrap();
423 assert_eq!(v.value, RonValue::String("say \"hi\"".to_string()));
424 }
425
426 #[test]
428 fn string_escaped_backslash() {
429 let mut p = parser("\"a\\\\b\"");
430 let v = p.parse_value().unwrap();
431 assert_eq!(v.value, RonValue::String("a\\b".to_string()));
432 }
433
434 #[test]
436 fn string_escaped_newline() {
437 let mut p = parser("\"line1\\nline2\"");
438 let v = p.parse_value().unwrap();
439 assert_eq!(v.value, RonValue::String("line1\nline2".to_string()));
440 }
441
442 #[test]
444 fn string_escaped_tab() {
445 let mut p = parser("\"col1\\tcol2\"");
446 let v = p.parse_value().unwrap();
447 assert_eq!(v.value, RonValue::String("col1\tcol2".to_string()));
448 }
449
450 #[test]
452 fn string_unterminated() {
453 let mut p = parser("\"hello");
454 let err = p.parse_value().unwrap_err();
455 assert_eq!(err.kind, RonErrorKind::UnterminatedString);
456 }
457
458 #[test]
464 fn integer_positive() {
465 let mut p = parser("42");
466 let v = p.parse_value().unwrap();
467 assert_eq!(v.value, RonValue::Integer(42));
468 }
469
470 #[test]
472 fn integer_zero() {
473 let mut p = parser("0");
474 let v = p.parse_value().unwrap();
475 assert_eq!(v.value, RonValue::Integer(0));
476 }
477
478 #[test]
480 fn integer_negative() {
481 let mut p = parser("-7");
482 let v = p.parse_value().unwrap();
483 assert_eq!(v.value, RonValue::Integer(-7));
484 }
485
486 #[test]
492 fn float_simple() {
493 let mut p = parser("3.14");
494 let v = p.parse_value().unwrap();
495 assert_eq!(v.value, RonValue::Float(3.14));
496 }
497
498 #[test]
500 fn float_negative() {
501 let mut p = parser("-0.5");
502 let v = p.parse_value().unwrap();
503 assert_eq!(v.value, RonValue::Float(-0.5));
504 }
505
506 #[test]
508 fn float_one_point_zero() {
509 let mut p = parser("1.0");
510 let v = p.parse_value().unwrap();
511 assert_eq!(v.value, RonValue::Float(1.0));
512 }
513
514 #[test]
520 fn bool_true() {
521 let mut p = parser("true");
522 let v = p.parse_value().unwrap();
523 assert_eq!(v.value, RonValue::Bool(true));
524 }
525
526 #[test]
528 fn bool_false() {
529 let mut p = parser("false");
530 let v = p.parse_value().unwrap();
531 assert_eq!(v.value, RonValue::Bool(false));
532 }
533
534 #[test]
540 fn option_none() {
541 let mut p = parser("None");
542 let v = p.parse_value().unwrap();
543 assert_eq!(v.value, RonValue::Option(None));
544 }
545
546 #[test]
548 fn option_some_integer() {
549 let mut p = parser("Some(5)");
550 let v = p.parse_value().unwrap();
551 if let RonValue::Option(Some(inner)) = &v.value {
552 assert_eq!(inner.value, RonValue::Integer(5));
553 } else {
554 panic!("expected Option(Some(...))");
555 }
556 }
557
558 #[test]
560 fn option_some_string() {
561 let mut p = parser("Some(\"hi\")");
562 let v = p.parse_value().unwrap();
563 if let RonValue::Option(Some(inner)) = &v.value {
564 assert_eq!(inner.value, RonValue::String("hi".to_string()));
565 } else {
566 panic!("expected Option(Some(...))");
567 }
568 }
569
570 #[test]
576 fn identifier_bare() {
577 let mut p = parser("Creature");
578 let v = p.parse_value().unwrap();
579 assert_eq!(v.value, RonValue::Identifier("Creature".to_string()));
580 }
581
582 #[test]
584 fn identifier_another() {
585 let mut p = parser("Sentinels");
586 let v = p.parse_value().unwrap();
587 assert_eq!(v.value, RonValue::Identifier("Sentinels".to_string()));
588 }
589
590 #[test]
596 fn list_empty() {
597 let mut p = parser("[]");
598 let v = p.parse_value().unwrap();
599 if let RonValue::List(elems) = &v.value {
600 assert!(elems.is_empty());
601 } else {
602 panic!("expected List");
603 }
604 }
605
606 #[test]
608 fn list_single_element() {
609 let mut p = parser("[Creature]");
610 let v = p.parse_value().unwrap();
611 if let RonValue::List(elems) = &v.value {
612 assert_eq!(elems.len(), 1);
613 assert_eq!(elems[0].value, RonValue::Identifier("Creature".to_string()));
614 } else {
615 panic!("expected List");
616 }
617 }
618
619 #[test]
621 fn list_multiple_elements() {
622 let mut p = parser("[Creature, Trap, Artifact]");
623 let v = p.parse_value().unwrap();
624 if let RonValue::List(elems) = &v.value {
625 assert_eq!(elems.len(), 3);
626 } else {
627 panic!("expected List");
628 }
629 }
630
631 #[test]
633 fn list_trailing_comma() {
634 let mut p = parser("[Creature, Trap,]");
635 let v = p.parse_value().unwrap();
636 if let RonValue::List(elems) = &v.value {
637 assert_eq!(elems.len(), 2);
638 } else {
639 panic!("expected List");
640 }
641 }
642
643 #[test]
645 fn list_of_strings() {
646 let mut p = parser("[\"Vigilance\", \"Haste\"]");
647 let v = p.parse_value().unwrap();
648 if let RonValue::List(elems) = &v.value {
649 assert_eq!(elems.len(), 2);
650 assert_eq!(elems[0].value, RonValue::String("Vigilance".to_string()));
651 assert_eq!(elems[1].value, RonValue::String("Haste".to_string()));
652 } else {
653 panic!("expected List");
654 }
655 }
656
657 #[test]
663 fn struct_empty() {
664 let mut p = parser("()");
665 let v = p.parse_value().unwrap();
666 if let RonValue::Struct(s) = &v.value {
667 assert!(s.fields.is_empty());
668 } else {
669 panic!("expected Struct");
670 }
671 }
672
673 #[test]
675 fn struct_single_field() {
676 let mut p = parser("(name: \"Ashborn Hound\")");
677 let v = p.parse_value().unwrap();
678 if let RonValue::Struct(s) = &v.value {
679 assert_eq!(s.fields.len(), 1);
680 assert_eq!(s.fields[0].0.value, "name");
681 assert_eq!(s.fields[0].1.value, RonValue::String("Ashborn Hound".to_string()));
682 } else {
683 panic!("expected Struct");
684 }
685 }
686
687 #[test]
689 fn struct_multiple_fields() {
690 let mut p = parser("(name: \"foo\", age: 5)");
691 let v = p.parse_value().unwrap();
692 if let RonValue::Struct(s) = &v.value {
693 assert_eq!(s.fields.len(), 2);
694 } else {
695 panic!("expected Struct");
696 }
697 }
698
699 #[test]
701 fn struct_trailing_comma() {
702 let mut p = parser("(name: \"foo\",)");
703 let v = p.parse_value().unwrap();
704 if let RonValue::Struct(s) = &v.value {
705 assert_eq!(s.fields.len(), 1);
706 } else {
707 panic!("expected Struct");
708 }
709 }
710
711 #[test]
713 fn struct_close_span_captured() {
714 let mut p = parser("(x: 1)");
715 let v = p.parse_value().unwrap();
716 if let RonValue::Struct(s) = &v.value {
717 assert_eq!(s.close_span.start.offset, 5);
718 assert_eq!(s.close_span.end.offset, 6);
719 } else {
720 panic!("expected Struct");
721 }
722 }
723
724 #[test]
726 fn struct_nested() {
727 let mut p = parser("(cost: (generic: 2, sigil: 1))");
728 let v = p.parse_value().unwrap();
729 if let RonValue::Struct(s) = &v.value {
730 assert_eq!(s.fields.len(), 1);
731 assert_eq!(s.fields[0].0.value, "cost");
732 if let RonValue::Struct(inner) = &s.fields[0].1.value {
733 assert_eq!(inner.fields.len(), 2);
734 } else {
735 panic!("expected nested Struct");
736 }
737 } else {
738 panic!("expected Struct");
739 }
740 }
741
742 #[test]
748 fn whitespace_leading() {
749 let mut p = parser(" 42");
750 let v = p.parse_value().unwrap();
751 assert_eq!(v.value, RonValue::Integer(42));
752 }
753
754 #[test]
756 fn comment_before_value() {
757 let mut p = parser("// comment\n42");
758 let v = p.parse_value().unwrap();
759 assert_eq!(v.value, RonValue::Integer(42));
760 }
761
762 #[test]
768 fn span_starts_after_whitespace() {
769 let mut p = parser(" 42");
770 let v = p.parse_value().unwrap();
771 assert_eq!(v.span.start.offset, 2);
772 }
773
774 #[test]
776 fn span_covers_string() {
777 let mut p = parser("\"hello\"");
778 let v = p.parse_value().unwrap();
779 assert_eq!(v.span.start.offset, 0);
780 assert_eq!(v.span.end.offset, 7);
781 }
782
783 #[test]
789 fn error_empty_input() {
790 let mut p = parser("");
791 let err = p.parse_value().unwrap_err();
792 match err.kind {
793 RonErrorKind::UnexpectedToken { found, .. } => {
794 assert_eq!(found, "end of file");
795 }
796 other => panic!("expected UnexpectedToken, got {:?}", other),
797 }
798 }
799
800 #[test]
802 fn error_unexpected_char() {
803 let mut p = parser("@");
804 assert!(p.parse_value().is_err());
805 }
806
807 #[test]
813 fn ron_full_struct() {
814 let source = r#"(
815 name: "Ashborn Hound",
816 card_types: [Creature],
817 legendary: false,
818 power: Some(1),
819 toughness: None,
820 keywords: [],
821 flavor_text: "placeholder",
822 )"#;
823 let v = parse_ron(source).unwrap();
824 if let RonValue::Struct(s) = &v.value {
825 assert_eq!(s.fields.len(), 7);
826 assert_eq!(s.fields[0].0.value, "name");
827 assert_eq!(s.fields[0].1.value, RonValue::String("Ashborn Hound".to_string()));
828 } else {
829 panic!("expected Struct");
830 }
831 }
832
833 #[test]
839 fn map_empty() {
840 let mut p = parser("{}");
841 let v = p.parse_value().unwrap();
842 if let RonValue::Map(entries) = &v.value {
843 assert!(entries.is_empty());
844 } else {
845 panic!("expected Map");
846 }
847 }
848
849 #[test]
851 fn map_string_keys() {
852 let mut p = parser("{\"str\": 5, \"dex\": 3}");
853 let v = p.parse_value().unwrap();
854 if let RonValue::Map(entries) = &v.value {
855 assert_eq!(entries.len(), 2);
856 assert_eq!(entries[0].0.value, RonValue::String("str".to_string()));
857 assert_eq!(entries[0].1.value, RonValue::Integer(5));
858 } else {
859 panic!("expected Map");
860 }
861 }
862
863 #[test]
865 fn map_integer_keys() {
866 let mut p = parser("{1: \"one\", 2: \"two\"}");
867 let v = p.parse_value().unwrap();
868 if let RonValue::Map(entries) = &v.value {
869 assert_eq!(entries.len(), 2);
870 assert_eq!(entries[0].0.value, RonValue::Integer(1));
871 } else {
872 panic!("expected Map");
873 }
874 }
875
876 #[test]
878 fn map_trailing_comma() {
879 let mut p = parser("{\"a\": 1,}");
880 let v = p.parse_value().unwrap();
881 if let RonValue::Map(entries) = &v.value {
882 assert_eq!(entries.len(), 1);
883 } else {
884 panic!("expected Map");
885 }
886 }
887}