1#![expect(clippy::inline_always)]
3
4use alloc::boxed::Box;
5use alloc::collections::{BTreeMap, BTreeSet};
6use alloc::vec::Vec;
7use core::mem::replace;
8use core::primitive::str;
9
10use crate::edn::Edn;
11use crate::error::{Code, Error};
12
13#[cfg(feature = "arbitrary-nums")]
14use bigdecimal::BigDecimal;
15#[cfg(feature = "arbitrary-nums")]
16use num_bigint::BigInt;
17#[cfg(feature = "floats")]
18use ordered_float::OrderedFloat;
19
20#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
25#[non_exhaustive]
26pub enum NodeKind<'e> {
27 Vector(
28 Vec<Node<'e>>,
29 Vec<Discard<'e>>,
30 ),
31 Set(
32 Vec<Node<'e>>,
33 Vec<Discard<'e>>,
34 ),
35 Map(
36 Vec<(Node<'e>, Node<'e>)>,
37 Vec<Discard<'e>>,
38 ),
39 List(
40 Vec<Node<'e>>,
41 Vec<Discard<'e>>,
42 ),
43 Key(&'e str),
44 Symbol(&'e str),
45 Str(&'e str),
46 Int(i64),
47 Tagged(&'e str, Span, Box<Node<'e>>),
48 #[cfg(feature = "floats")]
49 Double(OrderedFloat<f64>),
50 Rational((i64, i64)),
51 #[cfg(feature = "arbitrary-nums")]
52 BigInt(BigInt),
53 #[cfg(feature = "arbitrary-nums")]
54 BigDec(BigDecimal),
55 Char(char),
56 Bool(bool),
57 #[default]
58 Nil,
59}
60
61#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
63pub struct Discard<'e>(pub Node<'e>, pub Span);
64
65#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
69pub struct Node<'e> {
70 pub kind: NodeKind<'e>,
71 pub span: Span,
72 pub leading_discards: Vec<Discard<'e>>,
73}
74
75impl<'e> Node<'e> {
76 pub const fn no_discards(kind: NodeKind<'e>, span: Span) -> Self {
78 Self { kind, span, leading_discards: Vec::new() }
79 }
80
81 #[inline]
82 pub const fn span(&self) -> Span {
83 self.span
84 }
85}
86
87#[cfg_attr(not(feature = "unstable"), expect(dead_code))]
133pub fn parse<'r, 'e: 'r>(reader: &'r mut SourceReader<'e>) -> Result<Node<'e>, Error> {
134 let start_pos = reader.read_pos;
135 let builder = NodeBuilder;
136 let parsed = {
137 let mut walker = Walker::new(reader);
138 parse_internal(&mut walker, &builder)?
139 };
140 Ok(parsed.unwrap_or_else(|| builder.nil(reader.span_from(start_pos))))
141}
142
143pub fn parse_as_edn(edn: &str) -> Result<(Edn<'_>, &str), Error> {
149 let mut source_reader = SourceReader::new(edn);
150 let start_pos = source_reader.read_pos;
151 let builder = EdnBuilder;
152 let parsed = {
153 let mut walker = Walker::new(&mut source_reader);
154 parse_internal(&mut walker, &builder)?
155 };
156 let parsed = parsed.unwrap_or_else(|| builder.nil(source_reader.span_from(start_pos)));
157 Ok((parsed, source_reader.remaining()))
158}
159
160#[cfg_attr(not(feature = "unstable"), expect(clippy::redundant_pub_crate))]
161pub(crate) fn parse_optional_edn(edn: &str) -> Result<(Option<Edn<'_>>, &str), Error> {
162 let mut source_reader = SourceReader::new(edn);
163 let parsed = {
164 let mut walker = Walker::new(&mut source_reader);
165 parse_internal(&mut walker, &EdnBuilder)?
166 };
167 Ok((parsed, source_reader.remaining()))
168}
169
170const DELIMITERS: [char; 8] = [',', ']', '}', ')', ';', '(', '[', '{'];
171
172fn is_token_boundary(c: char) -> bool {
173 c.is_whitespace() || DELIMITERS.contains(&c) || c == '"'
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
177pub struct Position {
178 pub line: usize,
179 pub column: usize,
180 pub ptr: usize,
181}
182
183impl Default for Position {
184 fn default() -> Self {
185 Self { line: 1, column: 1, ptr: 0 }
186 }
187}
188
189#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
190pub struct Span(pub Position, pub Position);
191
192impl Span {
193 pub const fn is_empty(&self) -> bool {
195 self.0.ptr == self.1.ptr
196 }
197}
198
199#[derive(Debug)]
201pub struct SourceReader<'s> {
202 slice: &'s str,
203 read_pos: Position,
205}
206
207impl<'e> SourceReader<'e> {
208 pub fn new(source: &'e str) -> Self {
209 Self { slice: source, read_pos: Position::default() }
210 }
211
212 #[inline(always)]
214 pub const fn span_from(&self, marker: Position) -> Span {
215 Span(marker, self.read_pos)
216 }
217
218 pub fn remaining(&self) -> &'e str {
231 &self.slice[self.read_pos.ptr..]
232 }
233
234 #[cfg_attr(not(feature = "unstable"), expect(dead_code))]
260 pub const fn finish(self) -> (Position, &'e str) {
261 (self.read_pos, self.slice)
262 }
263
264 #[inline(always)]
266 fn slurp_literal(&mut self) -> &'e str {
267 let token = self.slice[self.read_pos.ptr..]
268 .split(is_token_boundary)
269 .next()
270 .expect("Expected at least an empty slice");
271
272 self.read_pos.ptr += token.len();
273 self.read_pos.column += token.chars().count();
274 token
275 }
276
277 #[inline(always)]
279 fn slurp_char(&mut self) -> &'e str {
280 let starting_ptr = self.read_pos.ptr;
281
282 let mut ptr = 0;
283 while let Some(c) = self.peek_next() {
284 if ptr > 1 && (c.is_whitespace() || DELIMITERS.contains(&c)) {
287 break;
288 }
289
290 let _ = self.nibble_next();
291 ptr += c.len_utf8();
292 }
293 &self.slice[starting_ptr..starting_ptr + ptr]
294 }
295
296 #[inline(always)]
297 fn slurp_str(&mut self) -> Result<&'e str, Error> {
298 let _ = self.nibble_next(); let starting_ptr = self.read_pos.ptr;
300 let mut escape = false;
301 loop {
302 if let Some(c) = self.nibble_next() {
303 if escape {
304 match c {
305 't' | 'r' | 'n' | '\\' | '"' => (),
306 _ => {
307 return Err(Error::from_position(Code::InvalidEscape, self.read_pos));
308 }
309 }
310 escape = false;
311 } else if c == '"' {
312 return Ok(&self.slice[starting_ptr..self.read_pos.ptr - 1]);
313 } else {
314 escape = c == '\\';
315 }
316 } else {
317 return Err(Error::from_position(Code::UnexpectedEOF, self.read_pos));
318 }
319 }
320 }
321
322 #[inline(always)]
323 fn slurp_tag(&mut self) -> Result<&'e str, Error> {
324 let starting_ptr = self.read_pos.ptr;
325
326 loop {
327 if let Some(c) = self.peek_next() {
328 if is_token_boundary(c) {
329 return Ok(&self.slice[starting_ptr..self.read_pos.ptr]);
330 }
331 let _ = self.nibble_next();
332 } else {
333 return Err(Error::from_position(Code::UnexpectedEOF, self.read_pos));
334 }
335 }
336 }
337
338 #[inline(always)]
340 fn nibble_newline(&mut self) {
341 while let Some(c) = self.peek_next() {
342 if matches!(c, '\n' | '\r') {
343 break;
344 }
345 let _ = self.nibble_next();
346 }
347 self.nibble_whitespace();
348 }
349
350 #[inline(always)]
352 fn nibble_whitespace(&mut self) {
353 while let Some(n) = self.peek_next() {
354 if n == ',' || n.is_whitespace() {
355 let _ = self.nibble_next();
356 continue;
357 }
358 break;
359 }
360 }
361
362 #[inline(always)]
364 fn nibble_next(&mut self) -> Option<char> {
365 let char = self.slice[self.read_pos.ptr..].chars().next();
366 if let Some(c) = char {
367 self.read_pos.ptr += c.len_utf8();
368 if c == '\n' {
369 self.read_pos.line += 1;
370 self.read_pos.column = 1;
371 } else {
372 self.read_pos.column += 1;
373 }
374 }
375 char
376 }
377
378 #[inline(always)]
380 fn peek_next(&self) -> Option<char> {
381 self.slice[self.read_pos.ptr..].chars().next()
382 }
383}
384
385struct Parsed<I> {
386 item: I,
387 span: Span,
388}
389
390impl<I> Parsed<I> {
391 const fn new(item: I, span: Span) -> Self {
392 Self { item, span }
393 }
394}
395
396struct Walker<'e, 'r, B: InternalParser<'e>> {
397 reader: &'r mut SourceReader<'e>,
398 stack: Vec<ParseContext<'e, B>>,
399}
400
401impl<'e, 'r, B: InternalParser<'e>> Walker<'e, 'r, B> {
402 fn new(reader: &'r mut SourceReader<'e>) -> Self {
403 Self {
404 reader,
405 stack: alloc::vec![ParseContext { kind: ContextKind::Top, discards: Vec::new() }],
406 }
407 }
408
409 #[inline(always)]
410 const fn pos(&self) -> Position {
411 self.reader.read_pos
412 }
413
414 #[inline(always)]
416 const fn span_from(&self, marker: Position) -> Span {
417 Span(marker, self.reader.read_pos)
418 }
419
420 #[inline(always)]
421 fn push_context(&mut self, ctx: ParseContext<'e, B>) {
422 self.stack.push(ctx);
423 }
424
425 #[inline(always)]
426 fn pop_context(&mut self) -> Option<ParseContext<'e, B>> {
427 self.stack.pop()
428 }
429
430 #[inline(always)]
431 const fn stack_len(&self) -> usize {
432 self.stack.len()
433 }
434
435 const fn make_error(&self, code: Code) -> Error {
436 Error::from_position(code, self.pos())
437 }
438
439 fn last_context_discards(&mut self) -> Option<&mut Vec<B::Discard>> {
440 match self.stack.last_mut() {
441 Some(ParseContext { discards, .. }) => Some(discards),
442 None => None,
443 }
444 }
445}
446
447#[derive(Debug, Clone, Copy)]
448enum OpenDelimiter {
449 Vector,
450 List,
451 Map,
452 Hash,
453}
454
455enum ContextKind<'e, B: InternalParser<'e>> {
457 Top,
458 Vector(B::VectorContext, Position),
459 List(B::ListContext, Position),
460 Map(B::MapContext, Position),
461 Set(B::SetContext, Position),
462 Tag(&'e str, Span, Position),
463 Discard(Position),
464}
465
466struct ParseContext<'e, B: InternalParser<'e>> {
467 kind: ContextKind<'e, B>,
468 discards: Vec<B::Discard>,
469}
470
471impl<'e, B: InternalParser<'e>> ParseContext<'e, B> {
472 const fn no_discards(kind: ContextKind<'e, B>) -> Self {
473 Self { kind, discards: Vec::new() }
474 }
475}
476
477#[derive(Debug, Clone)]
478#[cfg_attr(not(feature = "arbitrary-nums"), derive(Copy))]
479enum Atom<'e> {
480 Key(&'e str),
481 Symbol(&'e str),
482 Str(&'e str),
483 Int(i64),
484 #[cfg(feature = "floats")]
485 Double(OrderedFloat<f64>),
486 Rational((i64, i64)),
487 #[cfg(feature = "arbitrary-nums")]
488 BigInt(BigInt),
489 #[cfg(feature = "arbitrary-nums")]
490 BigDec(BigDecimal),
491 Char(char),
492 Bool(bool),
493 Nil,
494}
495
496trait InternalParser<'e> {
497 type Item;
498 type Discard;
499 type VectorContext;
500 type ListContext;
501 type MapContext;
502 type SetContext;
503
504 fn atom(&self, atom: Atom<'e>, span: Span) -> Self::Item;
505
506 fn with_leading_discards(
507 &self,
508 item: Self::Item,
509 leading_discards: Vec<Self::Discard>,
510 ) -> Self::Item;
511
512 fn new_vector_context(&self) -> Self::VectorContext;
513
514 fn new_list_context(&self) -> Self::ListContext;
515
516 fn new_map_context(&self) -> Self::MapContext;
517
518 fn new_set_context(&self) -> Self::SetContext;
519
520 fn add_to_vector(
521 &self,
522 ctx: &mut Self::VectorContext,
523 parsed: Parsed<Self::Item>,
524 leading_discards: Vec<Self::Discard>,
525 ) -> Result<(), Error>;
526
527 fn add_to_list(
528 &self,
529 ctx: &mut Self::ListContext,
530 parsed: Parsed<Self::Item>,
531 leading_discards: Vec<Self::Discard>,
532 ) -> Result<(), Error>;
533
534 fn add_to_map(
535 &self,
536 ctx: &mut Self::MapContext,
537 parsed: Parsed<Self::Item>,
538 leading_discards: Vec<Self::Discard>,
539 ) -> Result<(), Error>;
540
541 fn add_to_set(
542 &self,
543 ctx: &mut Self::SetContext,
544 parsed: Parsed<Self::Item>,
545 leading_discards: Vec<Self::Discard>,
546 ) -> Result<(), Error>;
547
548 fn finish_vector(
549 &self,
550 ctx: Self::VectorContext,
551 trailing_discards: Vec<Self::Discard>,
552 span: Span,
553 ) -> Result<Parsed<Self::Item>, Error>;
554
555 fn finish_set(
556 &self,
557 ctx: Self::SetContext,
558 trailing_discards: Vec<Self::Discard>,
559 validate: bool,
560 span: Span,
561 ) -> Result<Parsed<Self::Item>, Error>;
562
563 fn finish_map(
564 &self,
565 ctx: Self::MapContext,
566 trailing_discards: Vec<Self::Discard>,
567 validate: bool,
568 close_pos: Position,
569 span: Span,
570 ) -> Result<Parsed<Self::Item>, Error>;
571
572 fn finish_list(
573 &self,
574 ctx: Self::ListContext,
575 trailing_discards: Vec<Self::Discard>,
576 span: Span,
577 ) -> Result<Parsed<Self::Item>, Error>;
578
579 fn tag(
580 &self,
581 tag: &'e str,
582 tag_span: Span,
583 value: Parsed<Self::Item>,
584 leading_discards: Vec<Self::Discard>,
585 span: Span,
586 ) -> Result<Parsed<Self::Item>, Error>;
587
588 fn discard(
589 &self,
590 value: Parsed<Self::Item>,
591 leading_discards: Vec<Self::Discard>,
592 discard_span: Span,
593 ) -> Self::Discard;
594
595 fn nil(&self, span: Span) -> Self::Item {
596 self.atom(Atom::Nil, span)
597 }
598}
599
600struct EdnBuilder;
601
602impl<'e> InternalParser<'e> for EdnBuilder {
603 type Item = Edn<'e>;
604 type Discard = ();
605 type VectorContext = Vec<Edn<'e>>;
606 type ListContext = Vec<Edn<'e>>;
607 type MapContext = (Vec<(Parsed<Edn<'e>>, Parsed<Edn<'e>>)>, Option<Parsed<Edn<'e>>>);
608 type SetContext = Vec<Parsed<Edn<'e>>>;
609
610 fn atom(&self, atom: Atom<'e>, span: Span) -> Self::Item {
611 let _ = span;
612 match atom {
613 Atom::Key(key) => Edn::Key(key),
614 Atom::Symbol(symbol) => Edn::Symbol(symbol),
615 Atom::Str(str) => Edn::Str(str),
616 Atom::Int(int) => Edn::Int(int),
617 #[cfg(feature = "floats")]
618 Atom::Double(double) => Edn::Double(double),
619 Atom::Rational(rational) => Edn::Rational(rational),
620 #[cfg(feature = "arbitrary-nums")]
621 Atom::BigInt(big_int) => Edn::BigInt(big_int),
622 #[cfg(feature = "arbitrary-nums")]
623 Atom::BigDec(big_dec) => Edn::BigDec(big_dec),
624 Atom::Char(ch) => Edn::Char(ch),
625 Atom::Bool(bool) => Edn::Bool(bool),
626 Atom::Nil => Edn::Nil,
627 }
628 }
629
630 fn with_leading_discards(
631 &self,
632 item: Self::Item,
633 _leading_discards: Vec<Self::Discard>,
634 ) -> Self::Item {
635 item
636 }
637
638 fn new_vector_context(&self) -> Self::VectorContext {
639 Vec::new()
640 }
641
642 fn new_list_context(&self) -> Self::ListContext {
643 Vec::new()
644 }
645
646 fn new_map_context(&self) -> Self::MapContext {
647 (Vec::new(), None)
648 }
649
650 fn new_set_context(&self) -> Self::SetContext {
651 Vec::new()
652 }
653
654 fn add_to_vector(
655 &self,
656 ctx: &mut Self::VectorContext,
657 parsed: Parsed<Self::Item>,
658 _leading_discards: Vec<Self::Discard>,
659 ) -> Result<(), Error> {
660 ctx.push(parsed.item);
661 Ok(())
662 }
663
664 fn add_to_list(
665 &self,
666 ctx: &mut Self::ListContext,
667 parsed: Parsed<Self::Item>,
668 _leading_discards: Vec<Self::Discard>,
669 ) -> Result<(), Error> {
670 ctx.push(parsed.item);
671 Ok(())
672 }
673
674 fn add_to_map(
675 &self,
676 ctx: &mut Self::MapContext,
677 parsed: Parsed<Self::Item>,
678 _leading_discards: Vec<Self::Discard>,
679 ) -> Result<(), Error> {
680 let (entries, pending) = ctx;
681 if let Some(key) = pending.take() {
682 entries.push((key, parsed));
683 } else {
684 *pending = Some(parsed);
685 }
686 Ok(())
687 }
688
689 fn add_to_set(
690 &self,
691 ctx: &mut Self::SetContext,
692 parsed: Parsed<Self::Item>,
693 _leading_discards: Vec<Self::Discard>,
694 ) -> Result<(), Error> {
695 ctx.push(parsed);
696 Ok(())
697 }
698
699 fn finish_vector(
700 &self,
701 ctx: Self::VectorContext,
702 _trailing_discards: Vec<Self::Discard>,
703 span: Span,
704 ) -> Result<Parsed<Self::Item>, Error> {
705 Ok(Parsed::new(Edn::Vector(ctx), span))
706 }
707
708 fn finish_set(
709 &self,
710 ctx: Self::SetContext,
711 _trailing_discards: Vec<Self::Discard>,
712 validate: bool,
713 span: Span,
714 ) -> Result<Parsed<Self::Item>, Error> {
715 let mut set = BTreeSet::new();
716 for item in ctx {
717 if !set.insert(item.item) && validate {
718 return Err(Error::from_position(Code::SetDuplicateKey, item.span.1));
719 }
720 }
721 Ok(Parsed::new(Edn::Set(set), span))
722 }
723
724 fn finish_map(
725 &self,
726 ctx: Self::MapContext,
727 _trailing_discards: Vec<Self::Discard>,
728 validate: bool,
729 close_pos: Position,
730 span: Span,
731 ) -> Result<Parsed<Self::Item>, Error> {
732 if ctx.1.is_some() {
733 return Err(Error::from_position(Code::UnexpectedEOF, close_pos));
734 }
735 let mut map = BTreeMap::new();
736 for (key, value) in ctx.0 {
737 if map.insert(key.item, value.item).is_some() && validate {
738 return Err(Error::from_position(Code::HashMapDuplicateKey, value.span.1));
739 }
740 }
741 Ok(Parsed::new(Edn::Map(map), span))
742 }
743
744 fn finish_list(
745 &self,
746 ctx: Self::ListContext,
747 _trailing_discards: Vec<Self::Discard>,
748 span: Span,
749 ) -> Result<Parsed<Self::Item>, Error> {
750 Ok(Parsed::new(Edn::List(ctx), span))
751 }
752
753 fn tag(
754 &self,
755 tag: &'e str,
756 tag_span: Span,
757 value: Parsed<Self::Item>,
758 _leading_discards: Vec<Self::Discard>,
759 span: Span,
760 ) -> Result<Parsed<Self::Item>, Error> {
761 crate::edn::validate_tag(tag, tag_span)?;
762 if tag.starts_with(':') && !matches!(&value.item, Edn::Map(_)) {
763 return Err(Error::from_position(Code::InvalidTag, tag_span.0));
764 }
765 Ok(Parsed::new(Edn::Tagged(tag, Box::new(value.item)), span))
766 }
767
768 fn discard(
769 &self,
770 _value: Parsed<Self::Item>,
771 _leading_discards: Vec<Self::Discard>,
772 _discard_span: Span,
773 ) -> Self::Discard {
774 }
775}
776
777struct NodeBuilder;
778
779impl<'e> InternalParser<'e> for NodeBuilder {
780 type Item = Node<'e>;
781 type Discard = Discard<'e>;
782 type VectorContext = Vec<Node<'e>>;
783 type ListContext = Vec<Node<'e>>;
784 type MapContext = (Vec<(Node<'e>, Node<'e>)>, Option<Node<'e>>);
785 type SetContext = Vec<Node<'e>>;
786
787 fn atom(&self, atom: Atom<'e>, span: Span) -> Self::Item {
788 let kind = match atom {
789 Atom::Key(key) => NodeKind::Key(key),
790 Atom::Symbol(symbol) => NodeKind::Symbol(symbol),
791 Atom::Str(str) => NodeKind::Str(str),
792 Atom::Int(int) => NodeKind::Int(int),
793 #[cfg(feature = "floats")]
794 Atom::Double(double) => NodeKind::Double(double),
795 Atom::Rational(rational) => NodeKind::Rational(rational),
796 #[cfg(feature = "arbitrary-nums")]
797 Atom::BigInt(big_int) => NodeKind::BigInt(big_int),
798 #[cfg(feature = "arbitrary-nums")]
799 Atom::BigDec(big_dec) => NodeKind::BigDec(big_dec),
800 Atom::Char(ch) => NodeKind::Char(ch),
801 Atom::Bool(bool) => NodeKind::Bool(bool),
802 Atom::Nil => NodeKind::Nil,
803 };
804
805 Node::no_discards(kind, span)
806 }
807
808 fn with_leading_discards(
809 &self,
810 mut item: Self::Item,
811 leading_discards: Vec<Self::Discard>,
812 ) -> Self::Item {
813 item.leading_discards = leading_discards;
814 item
815 }
816
817 fn new_vector_context(&self) -> Self::VectorContext {
818 Vec::new()
819 }
820
821 fn new_list_context(&self) -> Self::ListContext {
822 Vec::new()
823 }
824
825 fn new_map_context(&self) -> Self::MapContext {
826 (Vec::new(), None)
827 }
828
829 fn new_set_context(&self) -> Self::SetContext {
830 Vec::new()
831 }
832
833 fn add_to_vector(
834 &self,
835 ctx: &mut Self::VectorContext,
836 parsed: Parsed<Self::Item>,
837 leading_discards: Vec<Self::Discard>,
838 ) -> Result<(), Error> {
839 ctx.push(self.with_leading_discards(parsed.item, leading_discards));
840 Ok(())
841 }
842
843 fn add_to_list(
844 &self,
845 ctx: &mut Self::ListContext,
846 parsed: Parsed<Self::Item>,
847 leading_discards: Vec<Self::Discard>,
848 ) -> Result<(), Error> {
849 ctx.push(self.with_leading_discards(parsed.item, leading_discards));
850 Ok(())
851 }
852
853 fn add_to_map(
854 &self,
855 ctx: &mut Self::MapContext,
856 parsed: Parsed<Self::Item>,
857 leading_discards: Vec<Self::Discard>,
858 ) -> Result<(), Error> {
859 let parsed = self.with_leading_discards(parsed.item, leading_discards);
860 if let Some(key) = ctx.1.take() {
861 ctx.0.push((key, parsed));
862 } else {
863 ctx.1 = Some(parsed);
864 }
865 Ok(())
866 }
867
868 fn add_to_set(
869 &self,
870 ctx: &mut Self::SetContext,
871 parsed: Parsed<Self::Item>,
872 leading_discards: Vec<Self::Discard>,
873 ) -> Result<(), Error> {
874 ctx.push(self.with_leading_discards(parsed.item, leading_discards));
875 Ok(())
876 }
877
878 fn finish_vector(
879 &self,
880 ctx: Self::VectorContext,
881 trailing_discards: Vec<Self::Discard>,
882 span: Span,
883 ) -> Result<Parsed<Self::Item>, Error> {
884 Ok(Parsed::new(Node::no_discards(NodeKind::Vector(ctx, trailing_discards), span), span))
885 }
886
887 fn finish_set(
888 &self,
889 ctx: Self::SetContext,
890 trailing_discards: Vec<Self::Discard>,
891 _validate: bool,
892 span: Span,
893 ) -> Result<Parsed<Self::Item>, Error> {
894 Ok(Parsed::new(Node::no_discards(NodeKind::Set(ctx, trailing_discards), span), span))
895 }
896
897 fn finish_map(
898 &self,
899 ctx: Self::MapContext,
900 trailing_discards: Vec<Self::Discard>,
901 _validate: bool,
902 close_pos: Position,
903 span: Span,
904 ) -> Result<Parsed<Self::Item>, Error> {
905 if ctx.1.is_some() {
906 return Err(Error::from_position(Code::UnexpectedEOF, close_pos));
907 }
908 Ok(Parsed::new(Node::no_discards(NodeKind::Map(ctx.0, trailing_discards), span), span))
909 }
910
911 fn finish_list(
912 &self,
913 ctx: Self::ListContext,
914 trailing_discards: Vec<Self::Discard>,
915 span: Span,
916 ) -> Result<Parsed<Self::Item>, Error> {
917 Ok(Parsed::new(Node::no_discards(NodeKind::List(ctx, trailing_discards), span), span))
918 }
919
920 fn tag(
921 &self,
922 tag: &'e str,
923 tag_span: Span,
924 value: Parsed<Self::Item>,
925 leading_discards: Vec<Self::Discard>,
926 span: Span,
927 ) -> Result<Parsed<Self::Item>, Error> {
928 let value = self.with_leading_discards(value.item, leading_discards);
929 Ok(Parsed::new(Node::no_discards(NodeKind::Tagged(tag, tag_span, Box::new(value)), span), span))
930 }
931
932 fn discard(
933 &self,
934 value: Parsed<Self::Item>,
935 leading_discards: Vec<Self::Discard>,
936 discard_span: Span,
937 ) -> Self::Discard {
938 Discard(self.with_leading_discards(value.item, leading_discards), discard_span)
939 }
940}
941
942#[expect(clippy::mem_replace_with_default)]
943const fn take_discards<D>(discards: &mut Vec<D>) -> Vec<D> {
944 replace(discards, Vec::new())
945}
946
947#[inline]
948fn add_to_context<'e, B: InternalParser<'e>>(
949 context: &mut Option<&mut ParseContext<'e, B>>,
950 builder: &B,
951 parsed: Parsed<B::Item>,
952) -> Result<(), Error> {
953 match context.as_mut() {
954 Some(ParseContext { kind: ContextKind::Vector(ctx, _), discards }) => {
955 builder.add_to_vector(ctx, parsed, take_discards(discards))?;
956 }
957 Some(ParseContext { kind: ContextKind::List(ctx, _), discards }) => {
958 builder.add_to_list(ctx, parsed, take_discards(discards))?;
959 }
960 Some(ParseContext { kind: ContextKind::Map(ctx, _), discards }) => {
961 builder.add_to_map(ctx, parsed, take_discards(discards))?;
962 }
963 Some(ParseContext { kind: ContextKind::Set(ctx, _), discards }) => {
964 builder.add_to_set(ctx, parsed, take_discards(discards))?;
965 }
966 _ => {}
967 }
968 Ok(())
969}
970
971#[inline]
972fn handle_open_delimiter<'e, B: InternalParser<'e>>(
973 walker: &mut Walker<'e, '_, B>,
974 builder: &B,
975 delim: OpenDelimiter,
976) -> Result<(), Error> {
977 let pos_start = walker.pos();
978 match delim {
979 OpenDelimiter::Vector => {
980 let _ = walker.reader.nibble_next();
981 walker.push_context(ParseContext::no_discards(ContextKind::Vector(
982 builder.new_vector_context(),
983 pos_start,
984 )));
985 }
986 OpenDelimiter::List => {
987 let _ = walker.reader.nibble_next();
988 walker.push_context(ParseContext::no_discards(ContextKind::List(
989 builder.new_list_context(),
990 pos_start,
991 )));
992 }
993 OpenDelimiter::Map => {
994 let _ = walker.reader.nibble_next();
995 walker.push_context(ParseContext::no_discards(ContextKind::Map(
996 builder.new_map_context(),
997 pos_start,
998 )));
999 }
1000 OpenDelimiter::Hash => {
1001 let _ = walker.reader.nibble_next();
1002 match walker.reader.peek_next() {
1003 Some('{') => {
1004 let _ = walker.reader.nibble_next();
1005 walker.push_context(ParseContext::no_discards(ContextKind::Set(
1006 builder.new_set_context(),
1007 pos_start,
1008 )));
1009 }
1010 Some('_') => {
1011 let _ = walker.reader.nibble_next();
1012 walker.push_context(ParseContext::no_discards(ContextKind::Discard(pos_start)));
1013 }
1014 Some(c) if !c.is_whitespace() && !DELIMITERS.contains(&c) => {
1015 let tag_pos_start = walker.pos();
1016 let tag = walker.reader.slurp_tag()?;
1017 let tag_span = walker.span_from(tag_pos_start);
1018 if tag.is_empty() {
1019 return Err(walker.make_error(Code::InvalidTag));
1020 }
1021
1022 walker.reader.nibble_whitespace();
1023 walker
1024 .push_context(ParseContext::no_discards(ContextKind::Tag(tag, tag_span, pos_start)));
1025 }
1026 Some(_) => return Err(walker.make_error(Code::InvalidTag)),
1027 None => return Err(walker.make_error(Code::UnexpectedEOF)),
1028 }
1029 }
1030 }
1031 Ok(())
1032}
1033
1034fn wrap_pending_tags<'e, 'r, B: InternalParser<'e>>(
1035 walker: &mut Walker<'e, 'r, B>,
1036 builder: &B,
1037 mut parsed: Parsed<B::Item>,
1038) -> Result<Parsed<B::Item>, Error> {
1039 while matches!(walker.stack.last(), Some(ParseContext { kind: ContextKind::Tag(..), .. })) {
1040 let ParseContext { kind: ContextKind::Tag(tag, tag_span, pos_start), discards } =
1041 walker.pop_context().expect("tag context should exist")
1042 else {
1043 unreachable!("tag context should be on top of the stack");
1044 };
1045
1046 parsed = builder.tag(tag, tag_span, parsed, discards, walker.span_from(pos_start))?;
1047 }
1048
1049 Ok(parsed)
1050}
1051
1052fn under_discard<'e, B: InternalParser<'e>>(walker: &Walker<'e, '_, B>) -> bool {
1053 walker.stack.iter().any(|ctx| matches!(ctx.kind, ContextKind::Discard(..)))
1054}
1055
1056fn complete_value<'e, 'r, B: InternalParser<'e>>(
1057 walker: &mut Walker<'e, 'r, B>,
1058 builder: &B,
1059 parsed: Parsed<B::Item>,
1060) -> Result<Option<B::Item>, Error> {
1061 let parsed = wrap_pending_tags(walker, builder, parsed)?;
1062
1063 if walker.stack_len() == 1 {
1064 let leading_discards =
1065 take_discards(walker.last_context_discards().expect("Top should be there"));
1066 return Ok(Some(builder.with_leading_discards(parsed.item, leading_discards)));
1067 }
1068
1069 if let Some(ParseContext { kind: ContextKind::Discard(pos_start), discards }) =
1070 walker.stack.last_mut()
1071 {
1072 let pos_start = *pos_start;
1073 let end_pos = parsed.span.1;
1074 let discarded = builder.discard(parsed, take_discards(discards), Span(pos_start, end_pos));
1075 walker.pop_context();
1076 walker.stack.last_mut().expect("Top should be there").discards.push(discarded);
1077 return Ok(None);
1078 }
1079
1080 add_to_context(&mut walker.stack.last_mut(), builder, parsed)?;
1081 Ok(None)
1082}
1083
1084#[inline]
1085fn handle_close_delimiter<'e, B: InternalParser<'e>>(
1086 walker: &mut Walker<'e, '_, B>,
1087 builder: &B,
1088 delimiter: char,
1089) -> Result<Option<B::Item>, Error> {
1090 if walker.stack_len() <= 1 {
1091 return Err(walker.make_error(Code::UnmatchedDelimiter(delimiter)));
1092 }
1093
1094 let expected = match walker.stack.last().expect("Len > 1 is never empty") {
1095 ParseContext { kind: ContextKind::Vector(..), .. } => ']',
1096 ParseContext { kind: ContextKind::List(..), .. } => ')',
1097 ParseContext { kind: ContextKind::Map(..) | ContextKind::Set(..), .. } => '}',
1098 _ => {
1099 return Err(walker.make_error(Code::UnmatchedDelimiter(delimiter)));
1100 }
1101 };
1102
1103 if delimiter != expected {
1104 return Err(walker.make_error(Code::UnmatchedDelimiter(delimiter)));
1105 }
1106
1107 let parsed = match walker.pop_context() {
1108 Some(ParseContext { kind: ContextKind::Vector(ctx, pos_start), discards }) => {
1109 let _ = walker.reader.nibble_next();
1110 builder.finish_vector(ctx, discards, walker.span_from(pos_start))?
1111 }
1112 Some(ParseContext { kind: ContextKind::List(ctx, pos_start), discards }) => {
1113 let _ = walker.reader.nibble_next();
1114 builder.finish_list(ctx, discards, walker.span_from(pos_start))?
1115 }
1116 Some(ParseContext { kind: ContextKind::Map(ctx, pos_start), discards }) => {
1117 let validate = !under_discard(walker);
1118 let close_pos = walker.pos();
1119 let _ = walker.reader.nibble_next();
1120 builder.finish_map(ctx, discards, validate, close_pos, walker.span_from(pos_start))?
1121 }
1122 Some(ParseContext { kind: ContextKind::Set(ctx, pos_start), discards }) => {
1123 let validate = !under_discard(walker);
1124 let _ = walker.reader.nibble_next();
1125 builder.finish_set(ctx, discards, validate, walker.span_from(pos_start))?
1126 }
1127 _ => {
1128 return Err(walker.make_error(Code::UnmatchedDelimiter(delimiter)));
1129 }
1130 };
1131
1132 complete_value(walker, builder, parsed)
1133}
1134
1135fn parse_internal<'e, B: InternalParser<'e>>(
1136 walker: &mut Walker<'e, '_, B>,
1137 builder: &B,
1138) -> Result<Option<B::Item>, Error> {
1139 let mut result = None;
1140 loop {
1141 walker.reader.nibble_whitespace();
1142 match walker.reader.peek_next() {
1143 Some(';') => walker.reader.nibble_newline(),
1144 Some('[') => handle_open_delimiter(walker, builder, OpenDelimiter::Vector)?,
1145 Some('(') => handle_open_delimiter(walker, builder, OpenDelimiter::List)?,
1146 Some('{') => handle_open_delimiter(walker, builder, OpenDelimiter::Map)?,
1147 Some('#') => handle_open_delimiter(walker, builder, OpenDelimiter::Hash)?,
1148 Some(d) if matches!(d, ']' | ')' | '}') => {
1149 if let Some(parsed) = handle_close_delimiter(walker, builder, d)? {
1150 result = Some(parsed);
1151 break;
1152 }
1153 }
1154 Some(c) => {
1155 let pos_start = walker.reader.read_pos;
1156 let atom = match c {
1157 '\\' => parse_char(walker.reader.slurp_char()).map(Atom::Char),
1158 '"' => Ok(Atom::Str(walker.reader.slurp_str()?)),
1159 _ => edn_literal(walker.reader.slurp_literal()),
1160 }
1161 .map_err(|code| Error::from_position(code, pos_start))?;
1162 let span = walker.reader.span_from(pos_start);
1163 let parsed = Parsed::new(builder.atom(atom, span), span);
1164
1165 if let Some(parsed) = complete_value(walker, builder, parsed)? {
1166 result = Some(parsed);
1167 break;
1168 }
1169 }
1170 None => {
1171 if walker.stack_len() > 1 {
1172 return Err(walker.make_error(Code::UnexpectedEOF));
1173 }
1174 break;
1175 }
1176 }
1177 }
1178 Ok(result)
1179}
1180
1181#[inline]
1182fn edn_literal(literal: &str) -> Result<Atom<'_>, Code> {
1183 fn numeric(s: &str) -> bool {
1184 let (first, second) = {
1185 let mut s = s.chars();
1186 (s.next(), s.next())
1187 };
1188
1189 let first = first.expect("Empty str is previously caught as nil");
1190 if first.is_numeric() {
1191 return true;
1192 }
1193
1194 if (first == '-' || first == '+')
1195 && let Some(s) = second
1196 && s.is_numeric()
1197 {
1198 return true;
1199 }
1200
1201 false
1202 }
1203
1204 Ok(match literal {
1205 "nil" => Atom::Nil,
1206 "true" => Atom::Bool(true),
1207 "false" => Atom::Bool(false),
1208 k if k.starts_with(':') => {
1209 if k.len() <= 1 {
1210 return Err(Code::InvalidKeyword);
1211 }
1212 Atom::Key(&k[1..])
1213 }
1214 n if numeric(n) => parse_number(n)?,
1215 _ => Atom::Symbol(literal),
1216 })
1217}
1218
1219#[inline]
1220fn parse_char(lit: &str) -> Result<char, Code> {
1221 let lit = &lit[1..]; match lit {
1223 "newline" => Ok('\n'),
1224 "return" => Ok('\r'),
1225 "tab" => Ok('\t'),
1226 "space" => Ok(' '),
1227 c if c.chars().count() == 1 => Ok(c.chars().next().expect("c must be one character")),
1228 _ => Err(Code::InvalidChar),
1229 }
1230}
1231
1232#[inline]
1233fn signed_int_from_slice(slice: &str, radix: u8, polarity: i8) -> Option<i64> {
1234 let magnitude = u64::from_str_radix(slice, radix.into()).ok()?;
1235 if polarity < 0 {
1236 if magnitude == (i64::MAX as u64) + 1 {
1237 return Some(i64::MIN);
1238 }
1239 i64::try_from(magnitude).ok().map(|n| -n)
1240 } else {
1241 i64::try_from(magnitude).ok()
1242 }
1243}
1244
1245#[inline]
1246fn parse_number(lit: &str) -> Result<Atom<'_>, Code> {
1247 let mut chars = lit.chars().peekable();
1248 let (number, radix, polarity) = {
1249 let mut num_ptr_start = 0;
1250 let polarity = chars.peek().map_or(1i8, |c| {
1251 if *c == '-' {
1252 num_ptr_start += 1;
1253 -1i8
1254 } else if *c == '+' {
1255 num_ptr_start += 1;
1257 1i8
1258 } else {
1259 1i8
1260 }
1261 });
1262
1263 let mut number = &lit[num_ptr_start..];
1264
1265 if number.get(..2).is_some_and(|prefix| prefix.eq_ignore_ascii_case("0x")) {
1266 number = &number[2..];
1267 (number, 16, polarity)
1268 } else if let Some(index) = number.find(['r', 'R']) {
1269 let radix = (number[0..index]).parse::<u8>();
1270
1271 match radix {
1272 Ok(r) => {
1273 if !(2..=36).contains(&r) {
1275 return Err(Code::InvalidRadix(Some(r)));
1276 }
1277
1278 number = &number[(index + 1)..];
1279 (number, r, polarity)
1280 }
1281 Err(_) => {
1282 return Err(Code::InvalidRadix(None));
1283 }
1284 }
1285 } else {
1286 (number, 10, polarity)
1287 }
1288 };
1289
1290 if let Some(n) = signed_int_from_slice(number, radix, polarity) {
1291 return Ok(Atom::Int(n));
1292 }
1293 if radix == 10
1294 && let Some(index) = number.find('/')
1295 {
1296 let (num, den) = number.split_at(index);
1297 let num = num.parse::<i64>();
1298 let den = &den[1..];
1299 let den_value = den.parse::<i64>();
1300
1301 if let (Ok(n), Ok(d)) = (num, den_value)
1302 && d > 0
1303 && !den.starts_with(['+', '-'])
1304 {
1305 return Ok(Atom::Rational((n * i64::from(polarity), d)));
1306 }
1307 }
1308
1309 #[cfg(feature = "arbitrary-nums")]
1310 if let Some(n) = big_int_from_slice(number, radix, polarity) {
1311 return Ok(Atom::BigInt(n));
1312 }
1313 #[cfg(feature = "floats")]
1314 if radix == 10
1315 && number.contains(['.', 'e', 'E'])
1316 && let Ok(n) = number.parse::<f64>()
1317 {
1318 return Ok(Atom::Double((n * f64::from(polarity)).into()));
1319 }
1320 #[cfg(feature = "arbitrary-nums")]
1321 if let Some(n) = big_dec_from_slice(number, radix, polarity) {
1322 return Ok(Atom::BigDec(n));
1323 }
1324
1325 Err(Code::InvalidNumber)
1326}
1327
1328#[inline]
1329#[cfg(feature = "arbitrary-nums")]
1330fn big_int_from_slice(slice: &str, radix: u8, polarity: i8) -> Option<num_bigint::BigInt> {
1331 let slice = slice.strip_suffix('N').map_or(slice, |slice| slice);
1333 let num = num_bigint::BigInt::parse_bytes(slice.as_bytes(), radix.into())?;
1334 Some(num * polarity)
1335}
1336
1337#[inline]
1338#[cfg(feature = "arbitrary-nums")]
1339fn big_dec_from_slice(slice: &str, radix: u8, polarity: i8) -> Option<bigdecimal::BigDecimal> {
1340 let slice = slice.strip_suffix('M').map_or(slice, |slice| slice);
1342 let num = bigdecimal::BigDecimal::parse_bytes(slice.as_bytes(), radix.into())?;
1343 Some(num * polarity)
1344}