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