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