1#[cfg(feature = "alloc")]
23use alloc::borrow::ToOwned;
24use core::fmt;
25
26use crate::stream::AsBStr;
27use crate::stream::Stream;
28#[allow(unused_imports)] use crate::Parser;
30
31pub use crate::stream::Needed;
32
33pub type Result<O, E = ContextError> = core::result::Result<O, E>;
39
40pub type ModalResult<O, E = ContextError> = Result<O, ErrMode<E>>;
51
52#[cfg(test)]
53pub(crate) type TestResult<I, O> = ModalResult<O, InputError<I>>;
54
55#[derive(Debug, Clone, PartialEq)]
63pub enum ErrMode<E> {
64 Incomplete(Needed),
73 Backtrack(E),
79 Cut(E),
88}
89
90impl<E> ErrMode<E> {
91 #[inline]
93 pub fn is_incomplete(&self) -> bool {
94 matches!(self, ErrMode::Incomplete(_))
95 }
96
97 pub fn cut(self) -> Self {
99 match self {
100 ErrMode::Backtrack(e) => ErrMode::Cut(e),
101 rest => rest,
102 }
103 }
104
105 pub fn backtrack(self) -> Self {
107 match self {
108 ErrMode::Cut(e) => ErrMode::Backtrack(e),
109 rest => rest,
110 }
111 }
112
113 pub fn map<E2, F>(self, f: F) -> ErrMode<E2>
115 where
116 F: FnOnce(E) -> E2,
117 {
118 match self {
119 ErrMode::Incomplete(n) => ErrMode::Incomplete(n),
120 ErrMode::Cut(t) => ErrMode::Cut(f(t)),
121 ErrMode::Backtrack(t) => ErrMode::Backtrack(f(t)),
122 }
123 }
124
125 pub fn convert<F>(self) -> ErrMode<F>
127 where
128 E: ErrorConvert<F>,
129 {
130 ErrorConvert::convert(self)
131 }
132
133 #[inline(always)]
137 pub fn into_inner(self) -> Result<E, Self> {
138 match self {
139 ErrMode::Backtrack(e) | ErrMode::Cut(e) => Ok(e),
140 err @ ErrMode::Incomplete(_) => Err(err),
141 }
142 }
143}
144
145impl<I: Stream, E: ParserError<I>> ParserError<I> for ErrMode<E> {
146 type Inner = E;
147
148 #[inline(always)]
149 fn from_input(input: &I) -> Self {
150 ErrMode::Backtrack(E::from_input(input))
151 }
152
153 #[inline(always)]
154 fn assert(input: &I, message: &'static str) -> Self
155 where
156 I: core::fmt::Debug,
157 {
158 ErrMode::Cut(E::assert(input, message))
159 }
160
161 #[inline(always)]
162 fn incomplete(_input: &I, needed: Needed) -> Self {
163 ErrMode::Incomplete(needed)
164 }
165
166 #[inline]
167 fn append(self, input: &I, token_start: &<I as Stream>::Checkpoint) -> Self {
168 match self {
169 ErrMode::Backtrack(e) => ErrMode::Backtrack(e.append(input, token_start)),
170 e => e,
171 }
172 }
173
174 fn or(self, other: Self) -> Self {
175 match (self, other) {
176 (ErrMode::Backtrack(e), ErrMode::Backtrack(o)) => ErrMode::Backtrack(e.or(o)),
177 (ErrMode::Incomplete(e), _) | (_, ErrMode::Incomplete(e)) => ErrMode::Incomplete(e),
178 (ErrMode::Cut(e), _) | (_, ErrMode::Cut(e)) => ErrMode::Cut(e),
179 }
180 }
181
182 #[inline(always)]
183 fn is_backtrack(&self) -> bool {
184 matches!(self, ErrMode::Backtrack(_))
185 }
186
187 #[inline(always)]
188 fn into_inner(self) -> Result<Self::Inner, Self> {
189 match self {
190 ErrMode::Backtrack(e) | ErrMode::Cut(e) => Ok(e),
191 err @ ErrMode::Incomplete(_) => Err(err),
192 }
193 }
194
195 #[inline(always)]
196 fn is_incomplete(&self) -> bool {
197 matches!(self, ErrMode::Incomplete(_))
198 }
199
200 #[inline(always)]
201 fn needed(&self) -> Option<Needed> {
202 match self {
203 ErrMode::Incomplete(needed) => Some(*needed),
204 _ => None,
205 }
206 }
207}
208
209impl<E> ModalError for ErrMode<E> {
210 fn cut(self) -> Self {
211 self.cut()
212 }
213
214 fn backtrack(self) -> Self {
215 self.backtrack()
216 }
217}
218
219impl<E1, E2> ErrorConvert<ErrMode<E2>> for ErrMode<E1>
220where
221 E1: ErrorConvert<E2>,
222{
223 #[inline(always)]
224 fn convert(self) -> ErrMode<E2> {
225 self.map(|e| e.convert())
226 }
227}
228
229impl<I, EXT, E> FromExternalError<I, EXT> for ErrMode<E>
230where
231 E: FromExternalError<I, EXT>,
232{
233 #[inline(always)]
234 fn from_external_error(input: &I, e: EXT) -> Self {
235 ErrMode::Backtrack(E::from_external_error(input, e))
236 }
237}
238
239impl<I: Stream, C, E: AddContext<I, C>> AddContext<I, C> for ErrMode<E> {
240 #[inline(always)]
241 fn add_context(self, input: &I, token_start: &<I as Stream>::Checkpoint, context: C) -> Self {
242 self.map(|err| err.add_context(input, token_start, context))
243 }
244}
245
246#[cfg(feature = "unstable-recover")]
247#[cfg(feature = "std")]
248impl<I: Stream, E1: FromRecoverableError<I, E2>, E2> FromRecoverableError<I, ErrMode<E2>>
249 for ErrMode<E1>
250{
251 #[inline]
252 fn from_recoverable_error(
253 token_start: &<I as Stream>::Checkpoint,
254 err_start: &<I as Stream>::Checkpoint,
255 input: &I,
256 e: ErrMode<E2>,
257 ) -> Self {
258 e.map(|e| E1::from_recoverable_error(token_start, err_start, input, e))
259 }
260}
261
262impl<T: Clone> ErrMode<InputError<T>> {
263 pub fn map_input<U: Clone, F>(self, f: F) -> ErrMode<InputError<U>>
265 where
266 F: FnOnce(T) -> U,
267 {
268 match self {
269 ErrMode::Incomplete(n) => ErrMode::Incomplete(n),
270 ErrMode::Cut(InputError { input }) => ErrMode::Cut(InputError { input: f(input) }),
271 ErrMode::Backtrack(InputError { input }) => {
272 ErrMode::Backtrack(InputError { input: f(input) })
273 }
274 }
275 }
276}
277
278impl<E: Eq> Eq for ErrMode<E> {}
279
280impl<E> fmt::Display for ErrMode<E>
281where
282 E: fmt::Debug,
283{
284 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
285 match self {
286 ErrMode::Incomplete(Needed::Size(u)) => write!(f, "Parsing requires {u} more data"),
287 ErrMode::Incomplete(Needed::Unknown) => write!(f, "Parsing requires more data"),
288 ErrMode::Cut(c) => write!(f, "Parsing Failure: {c:?}"),
289 ErrMode::Backtrack(c) => write!(f, "Parsing Error: {c:?}"),
290 }
291 }
292}
293
294pub trait ParserError<I: Stream>: Sized {
299 type Inner;
303
304 fn from_input(input: &I) -> Self;
306
307 #[inline(always)]
309 fn assert(input: &I, _message: &'static str) -> Self
310 where
311 I: core::fmt::Debug,
312 {
313 #[cfg(debug_assertions)]
314 panic!("assert `{_message}` failed at {input:#?}");
315 #[cfg(not(debug_assertions))]
316 Self::from_input(input)
317 }
318
319 #[inline(always)]
328 fn incomplete(input: &I, _needed: Needed) -> Self {
329 Self::from_input(input)
330 }
331
332 #[inline]
337 fn append(self, _input: &I, _token_start: &<I as Stream>::Checkpoint) -> Self {
338 self
339 }
340
341 #[inline]
346 fn or(self, other: Self) -> Self {
347 other
348 }
349
350 #[inline(always)]
352 fn is_backtrack(&self) -> bool {
353 true
354 }
355
356 fn into_inner(self) -> Result<Self::Inner, Self>;
358
359 #[inline(always)]
363 fn is_incomplete(&self) -> bool {
364 false
365 }
366
367 #[inline(always)]
372 fn needed(&self) -> Option<Needed> {
373 None
374 }
375}
376
377pub trait ModalError {
379 fn cut(self) -> Self;
381 fn backtrack(self) -> Self;
383}
384
385pub trait AddContext<I: Stream, C = &'static str>: Sized {
389 #[inline]
394 fn add_context(
395 self,
396 _input: &I,
397 _token_start: &<I as Stream>::Checkpoint,
398 _context: C,
399 ) -> Self {
400 self
401 }
402}
403
404#[cfg(feature = "unstable-recover")]
406#[cfg(feature = "std")]
407pub trait FromRecoverableError<I: Stream, E> {
408 fn from_recoverable_error(
410 token_start: &<I as Stream>::Checkpoint,
411 err_start: &<I as Stream>::Checkpoint,
412 input: &I,
413 e: E,
414 ) -> Self;
415}
416
417pub trait FromExternalError<I, E> {
421 fn from_external_error(input: &I, e: E) -> Self;
423}
424
425pub trait ErrorConvert<E> {
427 fn convert(self) -> E;
429}
430
431#[derive(Copy, Clone, Debug, Eq, PartialEq)]
443pub struct InputError<I: Clone> {
444 pub input: I,
446}
447
448impl<I: Clone> InputError<I> {
449 #[inline]
451 pub fn at(input: I) -> Self {
452 Self { input }
453 }
454
455 #[inline]
457 pub fn map_input<I2: Clone, O: Fn(I) -> I2>(self, op: O) -> InputError<I2> {
458 InputError {
459 input: op(self.input),
460 }
461 }
462}
463
464#[cfg(feature = "alloc")]
465impl<I: ToOwned> InputError<&I>
466where
467 <I as ToOwned>::Owned: Clone,
468{
469 pub fn into_owned(self) -> InputError<<I as ToOwned>::Owned> {
471 self.map_input(ToOwned::to_owned)
472 }
473}
474
475impl<I: Stream + Clone> ParserError<I> for InputError<I> {
476 type Inner = Self;
477
478 #[inline]
479 fn from_input(input: &I) -> Self {
480 Self {
481 input: input.clone(),
482 }
483 }
484
485 #[inline(always)]
486 fn into_inner(self) -> Result<Self::Inner, Self> {
487 Ok(self)
488 }
489}
490
491impl<I: Stream + Clone, C> AddContext<I, C> for InputError<I> {}
492
493#[cfg(feature = "unstable-recover")]
494#[cfg(feature = "std")]
495impl<I: Clone + Stream> FromRecoverableError<I, Self> for InputError<I> {
496 #[inline]
497 fn from_recoverable_error(
498 _token_start: &<I as Stream>::Checkpoint,
499 _err_start: &<I as Stream>::Checkpoint,
500 _input: &I,
501 e: Self,
502 ) -> Self {
503 e
504 }
505}
506
507impl<I: Clone, E> FromExternalError<I, E> for InputError<I> {
508 #[inline]
510 fn from_external_error(input: &I, _e: E) -> Self {
511 Self {
512 input: input.clone(),
513 }
514 }
515}
516
517impl<I: Clone + fmt::Display> fmt::Display for InputError<I> {
519 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
520 write!(f, "failed to parse starting at: {}", self.input)
521 }
522}
523
524#[cfg(feature = "std")]
525impl<I: Clone + fmt::Debug + fmt::Display + Sync + Send + 'static> std::error::Error
526 for InputError<I>
527{
528}
529
530#[derive(Copy, Clone, Debug, Eq, PartialEq)]
532pub struct EmptyError;
533
534impl<I: Stream> ParserError<I> for EmptyError {
535 type Inner = Self;
536
537 #[inline(always)]
538 fn from_input(_: &I) -> Self {
539 Self
540 }
541
542 #[inline(always)]
543 fn into_inner(self) -> Result<Self::Inner, Self> {
544 Ok(self)
545 }
546}
547
548impl<I: Stream, C> AddContext<I, C> for EmptyError {}
549
550#[cfg(feature = "unstable-recover")]
551#[cfg(feature = "std")]
552impl<I: Stream> FromRecoverableError<I, Self> for EmptyError {
553 #[inline(always)]
554 fn from_recoverable_error(
555 _token_start: &<I as Stream>::Checkpoint,
556 _err_start: &<I as Stream>::Checkpoint,
557 _input: &I,
558 e: Self,
559 ) -> Self {
560 e
561 }
562}
563
564impl<I, E> FromExternalError<I, E> for EmptyError {
565 #[inline(always)]
566 fn from_external_error(_input: &I, _e: E) -> Self {
567 Self
568 }
569}
570
571impl ErrorConvert<EmptyError> for EmptyError {
572 #[inline(always)]
573 fn convert(self) -> EmptyError {
574 self
575 }
576}
577
578impl core::fmt::Display for EmptyError {
579 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
580 "failed to parse".fmt(f)
581 }
582}
583
584impl<I: Stream> ParserError<I> for () {
585 type Inner = Self;
586
587 #[inline]
588 fn from_input(_: &I) -> Self {}
589
590 #[inline(always)]
591 fn into_inner(self) -> Result<Self::Inner, Self> {
592 Ok(self)
593 }
594}
595
596impl<I: Stream, C> AddContext<I, C> for () {}
597
598#[cfg(feature = "unstable-recover")]
599#[cfg(feature = "std")]
600impl<I: Stream> FromRecoverableError<I, Self> for () {
601 #[inline]
602 fn from_recoverable_error(
603 _token_start: &<I as Stream>::Checkpoint,
604 _err_start: &<I as Stream>::Checkpoint,
605 _input: &I,
606 (): Self,
607 ) -> Self {
608 }
609}
610
611impl<I, E> FromExternalError<I, E> for () {
612 #[inline]
613 fn from_external_error(_input: &I, _e: E) -> Self {}
614}
615
616impl ErrorConvert<()> for () {
617 #[inline]
618 fn convert(self) {}
619}
620
621#[derive(Debug)]
626pub struct ContextError<C = StrContext> {
627 #[cfg(feature = "alloc")]
628 context: alloc::vec::Vec<C>,
629 #[cfg(not(feature = "alloc"))]
630 context: core::marker::PhantomData<C>,
631 #[cfg(feature = "std")]
632 cause: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
633}
634
635impl<C> ContextError<C> {
636 #[inline]
638 pub fn new() -> Self {
639 Self {
640 context: Default::default(),
641 #[cfg(feature = "std")]
642 cause: None,
643 }
644 }
645
646 #[inline]
648 pub fn push(&mut self, context: C) {
649 #[cfg(feature = "alloc")]
650 self.context.push(context);
651 }
652
653 #[inline]
655 pub fn extend<I: IntoIterator<Item = C>>(&mut self, context: I) {
656 #[cfg(feature = "alloc")]
657 self.context.extend(context);
658 }
659
660 #[inline]
662 #[cfg(feature = "alloc")]
663 pub fn context(&self) -> impl Iterator<Item = &C> {
664 self.context.iter()
665 }
666
667 #[inline]
669 #[cfg(feature = "std")]
670 pub fn cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> {
671 self.cause.as_deref()
672 }
673}
674
675impl<C: Clone> Clone for ContextError<C> {
676 fn clone(&self) -> Self {
677 Self {
678 context: self.context.clone(),
679 #[cfg(feature = "std")]
680 cause: self.cause.as_ref().map(|e| e.to_string().into()),
681 }
682 }
683}
684
685impl<C> Default for ContextError<C> {
686 #[inline]
687 fn default() -> Self {
688 Self::new()
689 }
690}
691
692impl<I: Stream, C> ParserError<I> for ContextError<C> {
693 type Inner = Self;
694
695 #[inline]
696 fn from_input(_input: &I) -> Self {
697 Self::new()
698 }
699
700 #[inline(always)]
701 fn into_inner(self) -> Result<Self::Inner, Self> {
702 Ok(self)
703 }
704}
705
706impl<C, I: Stream> AddContext<I, C> for ContextError<C> {
707 #[inline]
708 fn add_context(
709 mut self,
710 _input: &I,
711 _token_start: &<I as Stream>::Checkpoint,
712 context: C,
713 ) -> Self {
714 self.push(context);
715 self
716 }
717}
718
719#[cfg(feature = "unstable-recover")]
720#[cfg(feature = "std")]
721impl<I: Stream, C> FromRecoverableError<I, Self> for ContextError<C> {
722 #[inline]
723 fn from_recoverable_error(
724 _token_start: &<I as Stream>::Checkpoint,
725 _err_start: &<I as Stream>::Checkpoint,
726 _input: &I,
727 e: Self,
728 ) -> Self {
729 e
730 }
731}
732
733#[cfg(feature = "std")]
734impl<C, I, E: std::error::Error + Send + Sync + 'static> FromExternalError<I, E>
735 for ContextError<C>
736{
737 #[inline]
738 fn from_external_error(_input: &I, e: E) -> Self {
739 let mut err = Self::new();
740 {
741 err.cause = Some(Box::new(e));
742 }
743 err
744 }
745}
746
747#[cfg(not(feature = "std"))]
749impl<C, I, E: Send + Sync + 'static> FromExternalError<I, E> for ContextError<C> {
750 #[inline]
751 fn from_external_error(_input: &I, _e: E) -> Self {
752 let err = Self::new();
753 err
754 }
755}
756
757impl<C: core::cmp::PartialEq> core::cmp::PartialEq for ContextError<C> {
759 fn eq(&self, other: &Self) -> bool {
760 #[cfg(feature = "alloc")]
761 {
762 if self.context != other.context {
763 return false;
764 }
765 }
766 #[cfg(feature = "std")]
767 {
768 if self.cause.as_ref().map(ToString::to_string)
769 != other.cause.as_ref().map(ToString::to_string)
770 {
771 return false;
772 }
773 }
774
775 true
776 }
777}
778
779impl core::fmt::Display for ContextError<StrContext> {
780 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
781 #[cfg(feature = "alloc")]
782 {
783 let expression = self.context().find_map(|c| match c {
784 StrContext::Label(c) => Some(c),
785 _ => None,
786 });
787 let expected = self
788 .context()
789 .filter_map(|c| match c {
790 StrContext::Expected(c) => Some(c),
791 _ => None,
792 })
793 .collect::<alloc::vec::Vec<_>>();
794
795 let mut newline = false;
796
797 if let Some(expression) = expression {
798 newline = true;
799
800 write!(f, "invalid {expression}")?;
801 }
802
803 if !expected.is_empty() {
804 if newline {
805 writeln!(f)?;
806 }
807 newline = true;
808
809 write!(f, "expected ")?;
810 for (i, expected) in expected.iter().enumerate() {
811 if i != 0 {
812 write!(f, ", ")?;
813 }
814 write!(f, "{expected}")?;
815 }
816 }
817 #[cfg(feature = "std")]
818 {
819 if let Some(cause) = self.cause() {
820 if newline {
821 writeln!(f)?;
822 }
823 write!(f, "{cause}")?;
824 }
825 }
826 }
827
828 Ok(())
829 }
830}
831
832impl<C> ErrorConvert<ContextError<C>> for ContextError<C> {
833 #[inline]
834 fn convert(self) -> ContextError<C> {
835 self
836 }
837}
838
839#[derive(Clone, Debug, PartialEq, Eq)]
841#[non_exhaustive]
842pub enum StrContext {
843 Label(&'static str),
845 Expected(StrContextValue),
847}
848
849impl core::fmt::Display for StrContext {
850 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
851 match self {
852 Self::Label(name) => write!(f, "invalid {name}"),
853 Self::Expected(value) => write!(f, "expected {value}"),
854 }
855 }
856}
857
858#[derive(Clone, Debug, PartialEq, Eq)]
860#[non_exhaustive]
861pub enum StrContextValue {
862 CharLiteral(char),
864 StringLiteral(&'static str),
866 Description(&'static str),
868}
869
870impl From<char> for StrContextValue {
871 #[inline]
872 fn from(inner: char) -> Self {
873 Self::CharLiteral(inner)
874 }
875}
876
877impl From<&'static str> for StrContextValue {
878 #[inline]
879 fn from(inner: &'static str) -> Self {
880 Self::StringLiteral(inner)
881 }
882}
883
884impl core::fmt::Display for StrContextValue {
885 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
886 match self {
887 Self::CharLiteral('\n') => "newline".fmt(f),
888 Self::CharLiteral('`') => "'`'".fmt(f),
889 Self::CharLiteral(c) if c.is_ascii_control() => {
890 write!(f, "`{}`", c.escape_debug())
891 }
892 Self::CharLiteral(c) => write!(f, "`{c}`"),
893 Self::StringLiteral(c) => write!(f, "`{c}`"),
894 Self::Description(c) => write!(f, "{c}"),
895 }
896 }
897}
898
899#[derive(Debug)]
901#[cfg(feature = "std")]
902pub enum TreeError<I, C = StrContext> {
903 Base(TreeErrorBase<I>),
905 Stack {
907 base: Box<Self>,
909 stack: Vec<TreeErrorFrame<I, C>>,
911 },
912 Alt(Vec<Self>),
914}
915
916#[derive(Debug)]
918#[cfg(feature = "std")]
919pub enum TreeErrorFrame<I, C = StrContext> {
920 Kind(TreeErrorBase<I>),
922 Context(TreeErrorContext<I, C>),
924}
925
926#[derive(Debug)]
928#[cfg(feature = "std")]
929pub struct TreeErrorBase<I> {
930 pub input: I,
932 pub cause: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
934}
935
936#[derive(Debug)]
938#[cfg(feature = "std")]
939pub struct TreeErrorContext<I, C = StrContext> {
940 pub input: I,
942 pub context: C,
944}
945
946#[cfg(feature = "std")]
947impl<I: ToOwned, C> TreeError<&I, C> {
948 pub fn into_owned(self) -> TreeError<<I as ToOwned>::Owned, C> {
950 self.map_input(ToOwned::to_owned)
951 }
952}
953
954#[cfg(feature = "std")]
955impl<I, C> TreeError<I, C> {
956 pub fn map_input<I2, O: Clone + Fn(I) -> I2>(self, op: O) -> TreeError<I2, C> {
958 match self {
959 TreeError::Base(base) => TreeError::Base(TreeErrorBase {
960 input: op(base.input),
961 cause: base.cause,
962 }),
963 TreeError::Stack { base, stack } => {
964 let base = Box::new(base.map_input(op.clone()));
965 let stack = stack
966 .into_iter()
967 .map(|frame| match frame {
968 TreeErrorFrame::Kind(kind) => TreeErrorFrame::Kind(TreeErrorBase {
969 input: op(kind.input),
970 cause: kind.cause,
971 }),
972 TreeErrorFrame::Context(context) => {
973 TreeErrorFrame::Context(TreeErrorContext {
974 input: op(context.input),
975 context: context.context,
976 })
977 }
978 })
979 .collect();
980 TreeError::Stack { base, stack }
981 }
982 TreeError::Alt(alt) => {
983 TreeError::Alt(alt.into_iter().map(|e| e.map_input(op.clone())).collect())
984 }
985 }
986 }
987
988 fn append_frame(self, frame: TreeErrorFrame<I, C>) -> Self {
989 match self {
990 TreeError::Stack { base, mut stack } => {
991 stack.push(frame);
992 TreeError::Stack { base, stack }
993 }
994 base => TreeError::Stack {
995 base: Box::new(base),
996 stack: vec![frame],
997 },
998 }
999 }
1000}
1001
1002#[cfg(feature = "std")]
1003impl<I, C> ParserError<I> for TreeError<I, C>
1004where
1005 I: Stream + Clone,
1006{
1007 type Inner = Self;
1008
1009 fn from_input(input: &I) -> Self {
1010 TreeError::Base(TreeErrorBase {
1011 input: input.clone(),
1012 cause: None,
1013 })
1014 }
1015
1016 fn append(self, input: &I, token_start: &<I as Stream>::Checkpoint) -> Self {
1017 let mut input = input.clone();
1018 input.reset(token_start);
1019 let frame = TreeErrorFrame::Kind(TreeErrorBase { input, cause: None });
1020 self.append_frame(frame)
1021 }
1022
1023 fn or(self, other: Self) -> Self {
1024 match (self, other) {
1025 (TreeError::Alt(mut first), TreeError::Alt(second)) => {
1026 first.extend(second);
1031 TreeError::Alt(first)
1032 }
1033 (TreeError::Alt(mut alt), new) | (new, TreeError::Alt(mut alt)) => {
1034 alt.push(new);
1035 TreeError::Alt(alt)
1036 }
1037 (first, second) => TreeError::Alt(vec![first, second]),
1038 }
1039 }
1040
1041 #[inline(always)]
1042 fn into_inner(self) -> Result<Self::Inner, Self> {
1043 Ok(self)
1044 }
1045}
1046
1047#[cfg(feature = "std")]
1048impl<I, C> AddContext<I, C> for TreeError<I, C>
1049where
1050 I: Stream + Clone,
1051{
1052 fn add_context(self, input: &I, token_start: &<I as Stream>::Checkpoint, context: C) -> Self {
1053 let mut input = input.clone();
1054 input.reset(token_start);
1055 let frame = TreeErrorFrame::Context(TreeErrorContext { input, context });
1056 self.append_frame(frame)
1057 }
1058}
1059
1060#[cfg(feature = "std")]
1061#[cfg(feature = "unstable-recover")]
1062impl<I: Stream, C> FromRecoverableError<I, Self> for TreeError<I, C> {
1063 #[inline]
1064 fn from_recoverable_error(
1065 _token_start: &<I as Stream>::Checkpoint,
1066 _err_start: &<I as Stream>::Checkpoint,
1067 _input: &I,
1068 e: Self,
1069 ) -> Self {
1070 e
1071 }
1072}
1073
1074#[cfg(feature = "std")]
1075impl<I, C, E: std::error::Error + Send + Sync + 'static> FromExternalError<I, E> for TreeError<I, C>
1076where
1077 I: Clone,
1078{
1079 fn from_external_error(input: &I, e: E) -> Self {
1080 TreeError::Base(TreeErrorBase {
1081 input: input.clone(),
1082 cause: Some(Box::new(e)),
1083 })
1084 }
1085}
1086
1087#[cfg(feature = "std")]
1088impl<I, C> ErrorConvert<TreeError<(I, usize), C>> for TreeError<I, C> {
1089 #[inline]
1090 fn convert(self) -> TreeError<(I, usize), C> {
1091 self.map_input(|i| (i, 0))
1092 }
1093}
1094
1095#[cfg(feature = "std")]
1096impl<I, C> ErrorConvert<TreeError<I, C>> for TreeError<(I, usize), C> {
1097 #[inline]
1098 fn convert(self) -> TreeError<I, C> {
1099 self.map_input(|(i, _o)| i)
1100 }
1101}
1102
1103#[cfg(feature = "std")]
1104impl<I, C> TreeError<I, C>
1105where
1106 I: core::fmt::Display,
1107 C: fmt::Display,
1108{
1109 fn write(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result {
1110 let child_indent = indent + 2;
1111 match self {
1112 TreeError::Base(base) => {
1113 writeln!(f, "{:indent$}{base}", "")?;
1114 }
1115 TreeError::Stack { base, stack } => {
1116 base.write(f, indent)?;
1117 for (level, frame) in stack.iter().enumerate() {
1118 match frame {
1119 TreeErrorFrame::Kind(frame) => {
1120 writeln!(f, "{:child_indent$}{level}: {frame}", "")?;
1121 }
1122 TreeErrorFrame::Context(frame) => {
1123 writeln!(f, "{:child_indent$}{level}: {frame}", "")?;
1124 }
1125 }
1126 }
1127 }
1128 TreeError::Alt(alt) => {
1129 writeln!(f, "{:indent$}during one of:", "")?;
1130 for child in alt {
1131 child.write(f, child_indent)?;
1132 }
1133 }
1134 }
1135
1136 Ok(())
1137 }
1138}
1139
1140#[cfg(feature = "std")]
1141impl<I: fmt::Display> fmt::Display for TreeErrorBase<I> {
1142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1143 if let Some(cause) = self.cause.as_ref() {
1144 write!(f, "caused by {cause}")?;
1145 }
1146 let input = abbreviate(self.input.to_string());
1147 write!(f, " at '{input}'")?;
1148 Ok(())
1149 }
1150}
1151
1152#[cfg(feature = "std")]
1153impl<I: fmt::Display, C: fmt::Display> fmt::Display for TreeErrorContext<I, C> {
1154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1155 let context = &self.context;
1156 let input = abbreviate(self.input.to_string());
1157 write!(f, "{context} at '{input}'")?;
1158 Ok(())
1159 }
1160}
1161
1162#[cfg(feature = "std")]
1163impl<I: fmt::Debug + fmt::Display + Sync + Send + 'static, C: fmt::Display + fmt::Debug>
1164 std::error::Error for TreeError<I, C>
1165{
1166}
1167
1168#[cfg(feature = "std")]
1169fn abbreviate(input: String) -> String {
1170 let mut abbrev = None;
1171
1172 if let Some((line, _)) = input.split_once('\n') {
1173 abbrev = Some(line);
1174 }
1175
1176 let max_len = 20;
1177 let current = abbrev.unwrap_or(&input);
1178 if max_len < current.len() {
1179 if let Some((index, _)) = current.char_indices().nth(max_len) {
1180 abbrev = Some(¤t[..index]);
1181 }
1182 }
1183
1184 if let Some(abbrev) = abbrev {
1185 format!("{abbrev}...")
1186 } else {
1187 input
1188 }
1189}
1190
1191#[cfg(feature = "std")]
1192impl<I: fmt::Display, C: fmt::Display> fmt::Display for TreeError<I, C> {
1193 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1194 self.write(f, 0)
1195 }
1196}
1197
1198#[derive(Clone, Debug, PartialEq, Eq)]
1200pub struct ParseError<I, E> {
1201 input: I,
1202 offset: usize,
1203 inner: E,
1204}
1205
1206impl<I: Stream, E: ParserError<I>> ParseError<I, E> {
1207 pub(crate) fn new(mut input: I, start: I::Checkpoint, inner: E) -> Self {
1208 let offset = input.offset_from(&start);
1209 input.reset(&start);
1210 Self {
1211 input,
1212 offset,
1213 inner,
1214 }
1215 }
1216}
1217
1218impl<I, E> ParseError<I, E> {
1219 #[inline]
1221 pub fn input(&self) -> &I {
1222 &self.input
1223 }
1224
1225 #[inline]
1236 pub fn offset(&self) -> usize {
1237 self.offset
1238 }
1239
1240 #[inline]
1242 pub fn inner(&self) -> &E {
1243 &self.inner
1244 }
1245
1246 #[inline]
1248 pub fn into_inner(self) -> E {
1249 self.inner
1250 }
1251}
1252
1253impl<I: AsBStr, E> ParseError<I, E> {
1254 #[inline]
1256 pub fn char_span(&self) -> core::ops::Range<usize> {
1257 char_boundary(self.input.as_bstr(), self.offset())
1258 }
1259}
1260
1261fn char_boundary(input: &[u8], offset: usize) -> core::ops::Range<usize> {
1262 let len = input.len();
1263 if offset == len {
1264 return offset..offset;
1265 }
1266
1267 let start = (0..(offset + 1).min(len))
1268 .rev()
1269 .find(|i| {
1270 input
1271 .get(*i)
1272 .copied()
1273 .map(is_utf8_char_boundary)
1274 .unwrap_or(false)
1275 })
1276 .unwrap_or(0);
1277 let end = (offset + 1..len)
1278 .find(|i| {
1279 input
1280 .get(*i)
1281 .copied()
1282 .map(is_utf8_char_boundary)
1283 .unwrap_or(false)
1284 })
1285 .unwrap_or(len);
1286 start..end
1287}
1288
1289const fn is_utf8_char_boundary(b: u8) -> bool {
1291 (b as i8) >= -0x40
1293}
1294
1295impl<I, E> core::fmt::Display for ParseError<I, E>
1296where
1297 I: AsBStr,
1298 E: core::fmt::Display,
1299{
1300 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1301 let input = self.input.as_bstr();
1302 let span_start = self.offset;
1303 let span_end = span_start;
1304 #[cfg(feature = "std")]
1305 if input.contains(&b'\n') {
1306 let (line_idx, col_idx) = translate_position(input, span_start);
1307 let line_num = line_idx + 1;
1308 let col_num = col_idx + 1;
1309 let gutter = line_num.to_string().len();
1310 let content = input
1311 .split(|c| *c == b'\n')
1312 .nth(line_idx)
1313 .expect("valid line number");
1314
1315 writeln!(f, "parse error at line {line_num}, column {col_num}")?;
1316 for _ in 0..gutter {
1318 write!(f, " ")?;
1319 }
1320 writeln!(f, " |")?;
1321
1322 write!(f, "{line_num} | ")?;
1324 writeln!(f, "{}", String::from_utf8_lossy(content))?;
1325
1326 for _ in 0..gutter {
1328 write!(f, " ")?;
1329 }
1330 write!(f, " | ")?;
1331 for _ in 0..col_idx {
1332 write!(f, " ")?;
1333 }
1334 write!(f, "^")?;
1337 for _ in (span_start + 1)..(span_end.min(span_start + content.len())) {
1338 write!(f, "^")?;
1339 }
1340 writeln!(f)?;
1341 } else {
1342 let content = input;
1343 writeln!(f, "{}", String::from_utf8_lossy(content))?;
1344 for _ in 0..span_start {
1345 write!(f, " ")?;
1346 }
1347 write!(f, "^")?;
1350 for _ in (span_start + 1)..(span_end.min(span_start + content.len())) {
1351 write!(f, "^")?;
1352 }
1353 writeln!(f)?;
1354 }
1355 write!(f, "{}", self.inner)?;
1356
1357 Ok(())
1358 }
1359}
1360
1361#[cfg(feature = "std")]
1362fn translate_position(input: &[u8], index: usize) -> (usize, usize) {
1363 if input.is_empty() {
1364 return (0, index);
1365 }
1366
1367 let safe_index = index.min(input.len() - 1);
1368 let column_offset = index - safe_index;
1369 let index = safe_index;
1370
1371 let nl = input[0..index]
1372 .iter()
1373 .rev()
1374 .enumerate()
1375 .find(|(_, b)| **b == b'\n')
1376 .map(|(nl, _)| index - nl - 1);
1377 let line_start = match nl {
1378 Some(nl) => nl + 1,
1379 None => 0,
1380 };
1381 let line = input[0..line_start].iter().filter(|b| **b == b'\n').count();
1382
1383 let column = core::str::from_utf8(&input[line_start..=index])
1385 .map(|s| s.chars().count() - 1)
1386 .unwrap_or_else(|_| index - line_start);
1387 let column = column + column_offset;
1388
1389 (line, column)
1390}
1391
1392#[cfg(test)]
1393mod test_char_boundary {
1394 use super::*;
1395
1396 #[test]
1397 fn ascii() {
1398 let input = "hi";
1399 let cases = [(0, 0..1), (1, 1..2), (2, 2..2)];
1400 for (offset, expected) in cases {
1401 assert_eq!(
1402 char_boundary(input.as_bytes(), offset),
1403 expected,
1404 "input={input:?}, offset={offset:?}"
1405 );
1406 }
1407 }
1408
1409 #[test]
1410 fn utf8() {
1411 let input = "βèƒôřè";
1412 assert_eq!(input.len(), 12);
1413 let cases = [
1414 (0, 0..2),
1415 (1, 0..2),
1416 (2, 2..4),
1417 (3, 2..4),
1418 (4, 4..6),
1419 (5, 4..6),
1420 (6, 6..8),
1421 (7, 6..8),
1422 (8, 8..10),
1423 (9, 8..10),
1424 (10, 10..12),
1425 (11, 10..12),
1426 (12, 12..12),
1427 ];
1428 for (offset, expected) in cases {
1429 assert_eq!(
1430 char_boundary(input.as_bytes(), offset),
1431 expected,
1432 "input={input:?}, offset={offset:?}"
1433 );
1434 }
1435 }
1436}
1437
1438#[cfg(test)]
1439#[cfg(feature = "std")]
1440mod test_parse_error {
1441 use super::*;
1442
1443 #[test]
1444 fn single_line() {
1445 let mut input = "0xZ123";
1446 let start = input.checkpoint();
1447 let _ = input.next_token().unwrap();
1448 let _ = input.next_token().unwrap();
1449 let inner = InputError::at(input);
1450 let error = ParseError::new(input, start, inner);
1451 let expected = "\
14520xZ123
1453 ^
1454failed to parse starting at: Z123";
1455 assert_eq!(error.to_string(), expected);
1456 }
1457}
1458
1459#[cfg(test)]
1460#[cfg(feature = "std")]
1461mod test_translate_position {
1462 use super::*;
1463
1464 #[test]
1465 fn empty() {
1466 let input = b"";
1467 let index = 0;
1468 let position = translate_position(&input[..], index);
1469 assert_eq!(position, (0, 0));
1470 }
1471
1472 #[test]
1473 fn start() {
1474 let input = b"Hello";
1475 let index = 0;
1476 let position = translate_position(&input[..], index);
1477 assert_eq!(position, (0, 0));
1478 }
1479
1480 #[test]
1481 fn end() {
1482 let input = b"Hello";
1483 let index = input.len() - 1;
1484 let position = translate_position(&input[..], index);
1485 assert_eq!(position, (0, input.len() - 1));
1486 }
1487
1488 #[test]
1489 fn after() {
1490 let input = b"Hello";
1491 let index = input.len();
1492 let position = translate_position(&input[..], index);
1493 assert_eq!(position, (0, input.len()));
1494 }
1495
1496 #[test]
1497 fn first_line() {
1498 let input = b"Hello\nWorld\n";
1499 let index = 2;
1500 let position = translate_position(&input[..], index);
1501 assert_eq!(position, (0, 2));
1502 }
1503
1504 #[test]
1505 fn end_of_line() {
1506 let input = b"Hello\nWorld\n";
1507 let index = 5;
1508 let position = translate_position(&input[..], index);
1509 assert_eq!(position, (0, 5));
1510 }
1511
1512 #[test]
1513 fn start_of_second_line() {
1514 let input = b"Hello\nWorld\n";
1515 let index = 6;
1516 let position = translate_position(&input[..], index);
1517 assert_eq!(position, (1, 0));
1518 }
1519
1520 #[test]
1521 fn second_line() {
1522 let input = b"Hello\nWorld\n";
1523 let index = 8;
1524 let position = translate_position(&input[..], index);
1525 assert_eq!(position, (1, 2));
1526 }
1527}