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 pub fn push(&mut self, context: C) {
704 #[cfg(feature = "alloc")]
705 self.context.push(context);
706 }
707
708 #[inline]
710 pub fn extend<I: IntoIterator<Item = C>>(&mut self, context: I) {
711 #[cfg(feature = "alloc")]
712 self.context.extend(context);
713 }
714
715 #[inline]
717 #[cfg(feature = "alloc")]
718 pub fn context(&self) -> impl Iterator<Item = &C> {
719 self.context.iter()
720 }
721
722 #[inline]
724 #[cfg(feature = "std")]
725 pub fn cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> {
726 self.cause.as_deref()
727 }
728}
729
730impl<C: Clone> Clone for ContextError<C> {
731 fn clone(&self) -> Self {
732 Self {
733 context: self.context.clone(),
734 #[cfg(feature = "std")]
735 cause: self.cause.as_ref().map(|e| e.to_string().into()),
736 }
737 }
738}
739
740impl<C> Default for ContextError<C> {
741 #[inline]
742 fn default() -> Self {
743 Self::new()
744 }
745}
746
747impl<I: Stream, C> ParserError<I> for ContextError<C> {
748 type Inner = Self;
749
750 #[inline]
751 fn from_input(_input: &I) -> Self {
752 Self::new()
753 }
754
755 #[inline(always)]
756 fn into_inner(self) -> Result<Self::Inner, Self> {
757 Ok(self)
758 }
759}
760
761impl<C, I: Stream> AddContext<I, C> for ContextError<C> {
762 #[inline]
763 fn add_context(
764 mut self,
765 _input: &I,
766 _token_start: &<I as Stream>::Checkpoint,
767 context: C,
768 ) -> Self {
769 self.push(context);
770 self
771 }
772}
773
774#[cfg(feature = "unstable-recover")]
775#[cfg(feature = "std")]
776impl<I: Stream, C> FromRecoverableError<I, Self> for ContextError<C> {
777 #[inline]
778 fn from_recoverable_error(
779 _token_start: &<I as Stream>::Checkpoint,
780 _err_start: &<I as Stream>::Checkpoint,
781 _input: &I,
782 e: Self,
783 ) -> Self {
784 e
785 }
786}
787
788#[cfg(feature = "std")]
789impl<C, I, E: std::error::Error + Send + Sync + 'static> FromExternalError<I, E>
790 for ContextError<C>
791{
792 #[inline]
793 fn from_external_error(_input: &I, e: E) -> Self {
794 let mut err = Self::new();
795 {
796 err.cause = Some(Box::new(e));
797 }
798 err
799 }
800}
801
802#[cfg(not(feature = "std"))]
804impl<C, I, E: Send + Sync + 'static> FromExternalError<I, E> for ContextError<C> {
805 #[inline]
806 fn from_external_error(_input: &I, _e: E) -> Self {
807 let err = Self::new();
808 err
809 }
810}
811
812impl<C: core::cmp::PartialEq> core::cmp::PartialEq for ContextError<C> {
814 fn eq(&self, other: &Self) -> bool {
815 #[cfg(feature = "alloc")]
816 {
817 if self.context != other.context {
818 return false;
819 }
820 }
821 #[cfg(feature = "std")]
822 {
823 if self.cause.as_ref().map(ToString::to_string)
824 != other.cause.as_ref().map(ToString::to_string)
825 {
826 return false;
827 }
828 }
829
830 true
831 }
832}
833
834impl crate::lib::std::fmt::Display for ContextError<StrContext> {
835 fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result {
836 #[cfg(feature = "alloc")]
837 {
838 let expression = self.context().find_map(|c| match c {
839 StrContext::Label(c) => Some(c),
840 _ => None,
841 });
842 let expected = self
843 .context()
844 .filter_map(|c| match c {
845 StrContext::Expected(c) => Some(c),
846 _ => None,
847 })
848 .collect::<crate::lib::std::vec::Vec<_>>();
849
850 let mut newline = false;
851
852 if let Some(expression) = expression {
853 newline = true;
854
855 write!(f, "invalid {expression}")?;
856 }
857
858 if !expected.is_empty() {
859 if newline {
860 writeln!(f)?;
861 }
862 newline = true;
863
864 write!(f, "expected ")?;
865 for (i, expected) in expected.iter().enumerate() {
866 if i != 0 {
867 write!(f, ", ")?;
868 }
869 write!(f, "{expected}")?;
870 }
871 }
872 #[cfg(feature = "std")]
873 {
874 if let Some(cause) = self.cause() {
875 if newline {
876 writeln!(f)?;
877 }
878 write!(f, "{cause}")?;
879 }
880 }
881 }
882
883 Ok(())
884 }
885}
886
887impl<C> ErrorConvert<ContextError<C>> for ContextError<C> {
888 #[inline]
889 fn convert(self) -> ContextError<C> {
890 self
891 }
892}
893
894#[derive(Clone, Debug, PartialEq, Eq)]
896#[non_exhaustive]
897pub enum StrContext {
898 Label(&'static str),
900 Expected(StrContextValue),
902}
903
904impl crate::lib::std::fmt::Display for StrContext {
905 fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result {
906 match self {
907 Self::Label(name) => write!(f, "invalid {name}"),
908 Self::Expected(value) => write!(f, "expected {value}"),
909 }
910 }
911}
912
913#[derive(Clone, Debug, PartialEq, Eq)]
915#[non_exhaustive]
916pub enum StrContextValue {
917 CharLiteral(char),
919 StringLiteral(&'static str),
921 Description(&'static str),
923}
924
925impl From<char> for StrContextValue {
926 #[inline]
927 fn from(inner: char) -> Self {
928 Self::CharLiteral(inner)
929 }
930}
931
932impl From<&'static str> for StrContextValue {
933 #[inline]
934 fn from(inner: &'static str) -> Self {
935 Self::StringLiteral(inner)
936 }
937}
938
939impl crate::lib::std::fmt::Display for StrContextValue {
940 fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result {
941 match self {
942 Self::CharLiteral('\n') => "newline".fmt(f),
943 Self::CharLiteral('`') => "'`'".fmt(f),
944 Self::CharLiteral(c) if c.is_ascii_control() => {
945 write!(f, "`{}`", c.escape_debug())
946 }
947 Self::CharLiteral(c) => write!(f, "`{c}`"),
948 Self::StringLiteral(c) => write!(f, "`{c}`"),
949 Self::Description(c) => write!(f, "{c}"),
950 }
951 }
952}
953
954#[derive(Debug)]
956#[cfg(feature = "std")]
957pub enum TreeError<I, C = StrContext> {
958 Base(TreeErrorBase<I>),
960 Stack {
962 base: Box<Self>,
964 stack: Vec<TreeErrorFrame<I, C>>,
966 },
967 Alt(Vec<Self>),
969}
970
971#[derive(Debug)]
973#[cfg(feature = "std")]
974pub enum TreeErrorFrame<I, C = StrContext> {
975 Kind(TreeErrorBase<I>),
977 Context(TreeErrorContext<I, C>),
979}
980
981#[derive(Debug)]
983#[cfg(feature = "std")]
984pub struct TreeErrorBase<I> {
985 pub input: I,
987 pub cause: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
989}
990
991#[derive(Debug)]
993#[cfg(feature = "std")]
994pub struct TreeErrorContext<I, C = StrContext> {
995 pub input: I,
997 pub context: C,
999}
1000
1001#[cfg(feature = "std")]
1002impl<I: ToOwned, C> TreeError<&I, C> {
1003 pub fn into_owned(self) -> TreeError<<I as ToOwned>::Owned, C> {
1005 self.map_input(ToOwned::to_owned)
1006 }
1007}
1008
1009#[cfg(feature = "std")]
1010impl<I, C> TreeError<I, C> {
1011 pub fn map_input<I2, O: Clone + Fn(I) -> I2>(self, op: O) -> TreeError<I2, C> {
1013 match self {
1014 TreeError::Base(base) => TreeError::Base(TreeErrorBase {
1015 input: op(base.input),
1016 cause: base.cause,
1017 }),
1018 TreeError::Stack { base, stack } => {
1019 let base = Box::new(base.map_input(op.clone()));
1020 let stack = stack
1021 .into_iter()
1022 .map(|frame| match frame {
1023 TreeErrorFrame::Kind(kind) => TreeErrorFrame::Kind(TreeErrorBase {
1024 input: op(kind.input),
1025 cause: kind.cause,
1026 }),
1027 TreeErrorFrame::Context(context) => {
1028 TreeErrorFrame::Context(TreeErrorContext {
1029 input: op(context.input),
1030 context: context.context,
1031 })
1032 }
1033 })
1034 .collect();
1035 TreeError::Stack { base, stack }
1036 }
1037 TreeError::Alt(alt) => {
1038 TreeError::Alt(alt.into_iter().map(|e| e.map_input(op.clone())).collect())
1039 }
1040 }
1041 }
1042
1043 fn append_frame(self, frame: TreeErrorFrame<I, C>) -> Self {
1044 match self {
1045 TreeError::Stack { base, mut stack } => {
1046 stack.push(frame);
1047 TreeError::Stack { base, stack }
1048 }
1049 base => TreeError::Stack {
1050 base: Box::new(base),
1051 stack: vec![frame],
1052 },
1053 }
1054 }
1055}
1056
1057#[cfg(feature = "std")]
1058impl<I, C> ParserError<I> for TreeError<I, C>
1059where
1060 I: Stream + Clone,
1061{
1062 type Inner = Self;
1063
1064 fn from_input(input: &I) -> Self {
1065 TreeError::Base(TreeErrorBase {
1066 input: input.clone(),
1067 cause: None,
1068 })
1069 }
1070
1071 fn append(self, input: &I, token_start: &<I as Stream>::Checkpoint) -> Self {
1072 let mut input = input.clone();
1073 input.reset(token_start);
1074 let frame = TreeErrorFrame::Kind(TreeErrorBase { input, cause: None });
1075 self.append_frame(frame)
1076 }
1077
1078 fn or(self, other: Self) -> Self {
1079 match (self, other) {
1080 (TreeError::Alt(mut first), TreeError::Alt(second)) => {
1081 first.extend(second);
1086 TreeError::Alt(first)
1087 }
1088 (TreeError::Alt(mut alt), new) | (new, TreeError::Alt(mut alt)) => {
1089 alt.push(new);
1090 TreeError::Alt(alt)
1091 }
1092 (first, second) => TreeError::Alt(vec![first, second]),
1093 }
1094 }
1095
1096 #[inline(always)]
1097 fn into_inner(self) -> Result<Self::Inner, Self> {
1098 Ok(self)
1099 }
1100}
1101
1102#[cfg(feature = "std")]
1103impl<I, C> AddContext<I, C> for TreeError<I, C>
1104where
1105 I: Stream + Clone,
1106{
1107 fn add_context(self, input: &I, token_start: &<I as Stream>::Checkpoint, context: C) -> Self {
1108 let mut input = input.clone();
1109 input.reset(token_start);
1110 let frame = TreeErrorFrame::Context(TreeErrorContext { input, context });
1111 self.append_frame(frame)
1112 }
1113}
1114
1115#[cfg(feature = "std")]
1116#[cfg(feature = "unstable-recover")]
1117impl<I: Stream, C> FromRecoverableError<I, Self> for TreeError<I, C> {
1118 #[inline]
1119 fn from_recoverable_error(
1120 _token_start: &<I as Stream>::Checkpoint,
1121 _err_start: &<I as Stream>::Checkpoint,
1122 _input: &I,
1123 e: Self,
1124 ) -> Self {
1125 e
1126 }
1127}
1128
1129#[cfg(feature = "std")]
1130impl<I, C, E: std::error::Error + Send + Sync + 'static> FromExternalError<I, E> for TreeError<I, C>
1131where
1132 I: Clone,
1133{
1134 fn from_external_error(input: &I, e: E) -> Self {
1135 TreeError::Base(TreeErrorBase {
1136 input: input.clone(),
1137 cause: Some(Box::new(e)),
1138 })
1139 }
1140}
1141
1142#[cfg(feature = "std")]
1143impl<I, C> ErrorConvert<TreeError<(I, usize), C>> for TreeError<I, C> {
1144 #[inline]
1145 fn convert(self) -> TreeError<(I, usize), C> {
1146 self.map_input(|i| (i, 0))
1147 }
1148}
1149
1150#[cfg(feature = "std")]
1151impl<I, C> ErrorConvert<TreeError<I, C>> for TreeError<(I, usize), C> {
1152 #[inline]
1153 fn convert(self) -> TreeError<I, C> {
1154 self.map_input(|(i, _o)| i)
1155 }
1156}
1157
1158#[cfg(feature = "std")]
1159impl<I, C> TreeError<I, C>
1160where
1161 I: crate::lib::std::fmt::Display,
1162 C: fmt::Display,
1163{
1164 fn write(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result {
1165 let child_indent = indent + 2;
1166 match self {
1167 TreeError::Base(base) => {
1168 writeln!(f, "{:indent$}{base}", "")?;
1169 }
1170 TreeError::Stack { base, stack } => {
1171 base.write(f, indent)?;
1172 for (level, frame) in stack.iter().enumerate() {
1173 match frame {
1174 TreeErrorFrame::Kind(frame) => {
1175 writeln!(f, "{:child_indent$}{level}: {frame}", "")?;
1176 }
1177 TreeErrorFrame::Context(frame) => {
1178 writeln!(f, "{:child_indent$}{level}: {frame}", "")?;
1179 }
1180 }
1181 }
1182 }
1183 TreeError::Alt(alt) => {
1184 writeln!(f, "{:indent$}during one of:", "")?;
1185 for child in alt {
1186 child.write(f, child_indent)?;
1187 }
1188 }
1189 }
1190
1191 Ok(())
1192 }
1193}
1194
1195#[cfg(feature = "std")]
1196impl<I: fmt::Display> fmt::Display for TreeErrorBase<I> {
1197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1198 if let Some(cause) = self.cause.as_ref() {
1199 write!(f, "caused by {cause}")?;
1200 }
1201 let input = abbreviate(self.input.to_string());
1202 write!(f, " at '{input}'")?;
1203 Ok(())
1204 }
1205}
1206
1207#[cfg(feature = "std")]
1208impl<I: fmt::Display, C: fmt::Display> fmt::Display for TreeErrorContext<I, C> {
1209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1210 let context = &self.context;
1211 let input = abbreviate(self.input.to_string());
1212 write!(f, "{context} at '{input}'")?;
1213 Ok(())
1214 }
1215}
1216
1217#[cfg(feature = "std")]
1218impl<I: fmt::Debug + fmt::Display + Sync + Send + 'static, C: fmt::Display + fmt::Debug>
1219 std::error::Error for TreeError<I, C>
1220{
1221}
1222
1223#[cfg(feature = "std")]
1224fn abbreviate(input: String) -> String {
1225 let mut abbrev = None;
1226
1227 if let Some((line, _)) = input.split_once('\n') {
1228 abbrev = Some(line);
1229 }
1230
1231 let max_len = 20;
1232 let current = abbrev.unwrap_or(&input);
1233 if max_len < current.len() {
1234 if let Some((index, _)) = current.char_indices().nth(max_len) {
1235 abbrev = Some(¤t[..index]);
1236 }
1237 }
1238
1239 if let Some(abbrev) = abbrev {
1240 format!("{abbrev}...")
1241 } else {
1242 input
1243 }
1244}
1245
1246#[cfg(feature = "std")]
1247impl<I: fmt::Display, C: fmt::Display> fmt::Display for TreeError<I, C> {
1248 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1249 self.write(f, 0)
1250 }
1251}
1252
1253#[derive(Clone, Debug, PartialEq, Eq)]
1255pub struct ParseError<I, E> {
1256 input: I,
1257 offset: usize,
1258 inner: E,
1259}
1260
1261impl<I: Stream, E: ParserError<I>> ParseError<I, E> {
1262 pub(crate) fn new(mut input: I, start: I::Checkpoint, inner: E) -> Self {
1263 let offset = input.offset_from(&start);
1264 input.reset(&start);
1265 Self {
1266 input,
1267 offset,
1268 inner,
1269 }
1270 }
1271}
1272
1273impl<I, E> ParseError<I, E> {
1274 #[inline]
1276 pub fn input(&self) -> &I {
1277 &self.input
1278 }
1279
1280 #[inline]
1291 pub fn offset(&self) -> usize {
1292 self.offset
1293 }
1294
1295 #[inline]
1297 pub fn inner(&self) -> &E {
1298 &self.inner
1299 }
1300
1301 #[inline]
1303 pub fn into_inner(self) -> E {
1304 self.inner
1305 }
1306}
1307
1308impl<I: AsBStr, E> ParseError<I, E> {
1309 #[inline]
1311 pub fn char_span(&self) -> crate::lib::std::ops::Range<usize> {
1312 char_boundary(self.input.as_bstr(), self.offset())
1313 }
1314}
1315
1316fn char_boundary(input: &[u8], offset: usize) -> crate::lib::std::ops::Range<usize> {
1317 let len = input.len();
1318 if offset == len {
1319 return offset..offset;
1320 }
1321
1322 let start = (0..(offset + 1).min(len))
1323 .rev()
1324 .find(|i| {
1325 input
1326 .get(*i)
1327 .copied()
1328 .map(is_utf8_char_boundary)
1329 .unwrap_or(false)
1330 })
1331 .unwrap_or(0);
1332 let end = (offset + 1..len)
1333 .find(|i| {
1334 input
1335 .get(*i)
1336 .copied()
1337 .map(is_utf8_char_boundary)
1338 .unwrap_or(false)
1339 })
1340 .unwrap_or(len);
1341 start..end
1342}
1343
1344const fn is_utf8_char_boundary(b: u8) -> bool {
1346 (b as i8) >= -0x40
1348}
1349
1350impl<I, E> core::fmt::Display for ParseError<I, E>
1351where
1352 I: AsBStr,
1353 E: core::fmt::Display,
1354{
1355 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1356 let input = self.input.as_bstr();
1357 let span_start = self.offset;
1358 let span_end = span_start;
1359 #[cfg(feature = "std")]
1360 if input.contains(&b'\n') {
1361 let (line_idx, col_idx) = translate_position(input, span_start);
1362 let line_num = line_idx + 1;
1363 let col_num = col_idx + 1;
1364 let gutter = line_num.to_string().len();
1365 let content = input
1366 .split(|c| *c == b'\n')
1367 .nth(line_idx)
1368 .expect("valid line number");
1369
1370 writeln!(f, "parse error at line {line_num}, column {col_num}")?;
1371 for _ in 0..gutter {
1373 write!(f, " ")?;
1374 }
1375 writeln!(f, " |")?;
1376
1377 write!(f, "{line_num} | ")?;
1379 writeln!(f, "{}", String::from_utf8_lossy(content))?;
1380
1381 for _ in 0..gutter {
1383 write!(f, " ")?;
1384 }
1385 write!(f, " | ")?;
1386 for _ in 0..col_idx {
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 } else {
1397 let content = input;
1398 writeln!(f, "{}", String::from_utf8_lossy(content))?;
1399 for _ in 0..span_start {
1400 write!(f, " ")?;
1401 }
1402 write!(f, "^")?;
1405 for _ in (span_start + 1)..(span_end.min(span_start + content.len())) {
1406 write!(f, "^")?;
1407 }
1408 writeln!(f)?;
1409 }
1410 write!(f, "{}", self.inner)?;
1411
1412 Ok(())
1413 }
1414}
1415
1416#[cfg(feature = "std")]
1417fn translate_position(input: &[u8], index: usize) -> (usize, usize) {
1418 if input.is_empty() {
1419 return (0, index);
1420 }
1421
1422 let safe_index = index.min(input.len() - 1);
1423 let column_offset = index - safe_index;
1424 let index = safe_index;
1425
1426 let nl = input[0..index]
1427 .iter()
1428 .rev()
1429 .enumerate()
1430 .find(|(_, b)| **b == b'\n')
1431 .map(|(nl, _)| index - nl - 1);
1432 let line_start = match nl {
1433 Some(nl) => nl + 1,
1434 None => 0,
1435 };
1436 let line = input[0..line_start].iter().filter(|b| **b == b'\n').count();
1437
1438 let column = crate::lib::std::str::from_utf8(&input[line_start..=index])
1440 .map(|s| s.chars().count() - 1)
1441 .unwrap_or_else(|_| index - line_start);
1442 let column = column + column_offset;
1443
1444 (line, column)
1445}
1446
1447#[cfg(test)]
1448mod test_char_boundary {
1449 use super::*;
1450
1451 #[test]
1452 fn ascii() {
1453 let input = "hi";
1454 let cases = [(0, 0..1), (1, 1..2), (2, 2..2)];
1455 for (offset, expected) in cases {
1456 assert_eq!(
1457 char_boundary(input.as_bytes(), offset),
1458 expected,
1459 "input={input:?}, offset={offset:?}"
1460 );
1461 }
1462 }
1463
1464 #[test]
1465 fn utf8() {
1466 let input = "βèƒôřè";
1467 assert_eq!(input.len(), 12);
1468 let cases = [
1469 (0, 0..2),
1470 (1, 0..2),
1471 (2, 2..4),
1472 (3, 2..4),
1473 (4, 4..6),
1474 (5, 4..6),
1475 (6, 6..8),
1476 (7, 6..8),
1477 (8, 8..10),
1478 (9, 8..10),
1479 (10, 10..12),
1480 (11, 10..12),
1481 (12, 12..12),
1482 ];
1483 for (offset, expected) in cases {
1484 assert_eq!(
1485 char_boundary(input.as_bytes(), offset),
1486 expected,
1487 "input={input:?}, offset={offset:?}"
1488 );
1489 }
1490 }
1491}
1492
1493#[cfg(test)]
1494#[cfg(feature = "std")]
1495mod test_parse_error {
1496 use super::*;
1497
1498 #[test]
1499 fn single_line() {
1500 let mut input = "0xZ123";
1501 let start = input.checkpoint();
1502 let _ = input.next_token().unwrap();
1503 let _ = input.next_token().unwrap();
1504 let inner = InputError::at(input);
1505 let error = ParseError::new(input, start, inner);
1506 let expected = "\
15070xZ123
1508 ^
1509failed to parse starting at: Z123";
1510 assert_eq!(error.to_string(), expected);
1511 }
1512}
1513
1514#[cfg(test)]
1515#[cfg(feature = "std")]
1516mod test_translate_position {
1517 use super::*;
1518
1519 #[test]
1520 fn empty() {
1521 let input = b"";
1522 let index = 0;
1523 let position = translate_position(&input[..], index);
1524 assert_eq!(position, (0, 0));
1525 }
1526
1527 #[test]
1528 fn start() {
1529 let input = b"Hello";
1530 let index = 0;
1531 let position = translate_position(&input[..], index);
1532 assert_eq!(position, (0, 0));
1533 }
1534
1535 #[test]
1536 fn end() {
1537 let input = b"Hello";
1538 let index = input.len() - 1;
1539 let position = translate_position(&input[..], index);
1540 assert_eq!(position, (0, input.len() - 1));
1541 }
1542
1543 #[test]
1544 fn after() {
1545 let input = b"Hello";
1546 let index = input.len();
1547 let position = translate_position(&input[..], index);
1548 assert_eq!(position, (0, input.len()));
1549 }
1550
1551 #[test]
1552 fn first_line() {
1553 let input = b"Hello\nWorld\n";
1554 let index = 2;
1555 let position = translate_position(&input[..], index);
1556 assert_eq!(position, (0, 2));
1557 }
1558
1559 #[test]
1560 fn end_of_line() {
1561 let input = b"Hello\nWorld\n";
1562 let index = 5;
1563 let position = translate_position(&input[..], index);
1564 assert_eq!(position, (0, 5));
1565 }
1566
1567 #[test]
1568 fn start_of_second_line() {
1569 let input = b"Hello\nWorld\n";
1570 let index = 6;
1571 let position = translate_position(&input[..], index);
1572 assert_eq!(position, (1, 0));
1573 }
1574
1575 #[test]
1576 fn second_line() {
1577 let input = b"Hello\nWorld\n";
1578 let index = 8;
1579 let position = translate_position(&input[..], index);
1580 assert_eq!(position, (1, 2));
1581 }
1582}