1#[cfg(feature = "alloc")]
24use crate::lib::std::borrow::ToOwned;
25use crate::lib::std::fmt;
26use core::num::NonZeroUsize;
27
28use crate::stream::AsBStr;
29use crate::stream::Stream;
30#[allow(unused_imports)] use crate::Parser;
32
33pub type IResult<I, O, E = InputError<I>> = PResult<(I, O), E>;
45
46pub type PResult<O, E = ContextError> = Result<O, ErrMode<E>>;
57
58#[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)]
98pub enum ErrMode<E> {
99 Incomplete(Needed),
108 Backtrack(E),
114 Cut(E),
123}
124
125impl<E> ErrMode<E> {
126 #[inline]
128 pub fn is_incomplete(&self) -> bool {
129 matches!(self, ErrMode::Incomplete(_))
130 }
131
132 pub fn cut(self) -> Self {
134 match self {
135 ErrMode::Backtrack(e) => ErrMode::Cut(e),
136 rest => rest,
137 }
138 }
139
140 pub fn backtrack(self) -> Self {
142 match self {
143 ErrMode::Cut(e) => ErrMode::Backtrack(e),
144 rest => rest,
145 }
146 }
147
148 pub fn map<E2, F>(self, f: F) -> ErrMode<E2>
150 where
151 F: FnOnce(E) -> E2,
152 {
153 match self {
154 ErrMode::Incomplete(n) => ErrMode::Incomplete(n),
155 ErrMode::Cut(t) => ErrMode::Cut(f(t)),
156 ErrMode::Backtrack(t) => ErrMode::Backtrack(f(t)),
157 }
158 }
159
160 pub fn convert<F>(self) -> ErrMode<F>
162 where
163 E: ErrorConvert<F>,
164 {
165 self.map(ErrorConvert::convert)
166 }
167
168 #[cfg_attr(debug_assertions, track_caller)]
172 #[inline(always)]
173 pub fn into_inner(self) -> Option<E> {
174 match self {
175 ErrMode::Backtrack(e) | ErrMode::Cut(e) => Some(e),
176 ErrMode::Incomplete(_) => None,
177 }
178 }
179}
180
181impl<I: Stream, E: ParserError<I>> ParserError<I> for ErrMode<E> {
182 #[inline(always)]
183 fn from_error_kind(input: &I, kind: ErrorKind) -> Self {
184 ErrMode::Backtrack(E::from_error_kind(input, kind))
185 }
186
187 #[cfg_attr(debug_assertions, track_caller)]
188 #[inline(always)]
189 fn assert(input: &I, message: &'static str) -> Self
190 where
191 I: crate::lib::std::fmt::Debug,
192 {
193 ErrMode::Cut(E::assert(input, message))
194 }
195
196 #[inline]
197 fn append(self, input: &I, token_start: &<I as Stream>::Checkpoint, kind: ErrorKind) -> Self {
198 match self {
199 ErrMode::Backtrack(e) => ErrMode::Backtrack(e.append(input, token_start, kind)),
200 e => e,
201 }
202 }
203
204 fn or(self, other: Self) -> Self {
205 match (self, other) {
206 (ErrMode::Backtrack(e), ErrMode::Backtrack(o)) => ErrMode::Backtrack(e.or(o)),
207 (ErrMode::Incomplete(e), _) | (_, ErrMode::Incomplete(e)) => ErrMode::Incomplete(e),
208 (ErrMode::Cut(e), _) | (_, ErrMode::Cut(e)) => ErrMode::Cut(e),
209 }
210 }
211}
212
213impl<I, EXT, E> FromExternalError<I, EXT> for ErrMode<E>
214where
215 E: FromExternalError<I, EXT>,
216{
217 #[inline(always)]
218 fn from_external_error(input: &I, kind: ErrorKind, e: EXT) -> Self {
219 ErrMode::Backtrack(E::from_external_error(input, kind, e))
220 }
221}
222
223impl<I: Stream, C, E: AddContext<I, C>> AddContext<I, C> for ErrMode<E> {
224 #[inline(always)]
225 fn add_context(self, input: &I, token_start: &<I as Stream>::Checkpoint, context: C) -> Self {
226 self.map(|err| err.add_context(input, token_start, context))
227 }
228}
229
230impl<T: Clone> ErrMode<InputError<T>> {
231 pub fn map_input<U: Clone, F>(self, f: F) -> ErrMode<InputError<U>>
233 where
234 F: FnOnce(T) -> U,
235 {
236 match self {
237 ErrMode::Incomplete(n) => ErrMode::Incomplete(n),
238 ErrMode::Cut(InputError { input, kind }) => ErrMode::Cut(InputError {
239 input: f(input),
240 kind,
241 }),
242 ErrMode::Backtrack(InputError { input, kind }) => ErrMode::Backtrack(InputError {
243 input: f(input),
244 kind,
245 }),
246 }
247 }
248}
249
250impl<E: Eq> Eq for ErrMode<E> {}
251
252impl<E> fmt::Display for ErrMode<E>
253where
254 E: fmt::Debug,
255{
256 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257 match self {
258 ErrMode::Incomplete(Needed::Size(u)) => write!(f, "Parsing requires {u} more data"),
259 ErrMode::Incomplete(Needed::Unknown) => write!(f, "Parsing requires more data"),
260 ErrMode::Cut(c) => write!(f, "Parsing Failure: {c:?}"),
261 ErrMode::Backtrack(c) => write!(f, "Parsing Error: {c:?}"),
262 }
263 }
264}
265
266pub trait ParserError<I: Stream>: Sized {
271 fn from_error_kind(input: &I, kind: ErrorKind) -> Self;
273
274 #[cfg_attr(debug_assertions, track_caller)]
276 fn assert(input: &I, _message: &'static str) -> Self
277 where
278 I: crate::lib::std::fmt::Debug,
279 {
280 #[cfg(debug_assertions)]
281 panic!("assert `{_message}` failed at {input:#?}");
282 #[cfg(not(debug_assertions))]
283 Self::from_error_kind(input, ErrorKind::Assert)
284 }
285
286 fn append(self, input: &I, token_start: &<I as Stream>::Checkpoint, kind: ErrorKind) -> Self;
291
292 #[inline]
297 fn or(self, other: Self) -> Self {
298 other
299 }
300}
301
302pub trait AddContext<I: Stream, C = &'static str>: Sized {
306 #[inline]
311 fn add_context(
312 self,
313 _input: &I,
314 _token_start: &<I as Stream>::Checkpoint,
315 _context: C,
316 ) -> Self {
317 self
318 }
319}
320
321#[cfg(feature = "unstable-recover")]
323#[cfg(feature = "std")]
324pub trait FromRecoverableError<I: Stream, E> {
325 fn from_recoverable_error(
327 token_start: &<I as Stream>::Checkpoint,
328 err_start: &<I as Stream>::Checkpoint,
329 input: &I,
330 e: E,
331 ) -> Self;
332}
333
334pub trait FromExternalError<I, E> {
338 fn from_external_error(input: &I, kind: ErrorKind, e: E) -> Self;
340}
341
342pub trait ErrorConvert<E> {
344 fn convert(self) -> E;
346}
347
348#[derive(Copy, Clone, Debug, Eq, PartialEq)]
356pub struct InputError<I: Clone> {
357 pub input: I,
359 pub kind: ErrorKind,
361}
362
363impl<I: Clone> InputError<I> {
364 #[inline]
366 pub fn new(input: I, kind: ErrorKind) -> Self {
367 Self { input, kind }
368 }
369
370 #[inline]
372 pub fn map_input<I2: Clone, O: Fn(I) -> I2>(self, op: O) -> InputError<I2> {
373 InputError {
374 input: op(self.input),
375 kind: self.kind,
376 }
377 }
378}
379
380#[cfg(feature = "alloc")]
381impl<'i, I: ToOwned> InputError<&'i I>
382where
383 <I as ToOwned>::Owned: Clone,
384{
385 pub fn into_owned(self) -> InputError<<I as ToOwned>::Owned> {
387 self.map_input(ToOwned::to_owned)
388 }
389}
390
391impl<I: Stream + Clone> ParserError<I> for InputError<I> {
392 #[inline]
393 fn from_error_kind(input: &I, kind: ErrorKind) -> Self {
394 Self {
395 input: input.clone(),
396 kind,
397 }
398 }
399
400 #[inline]
401 fn append(
402 self,
403 _input: &I,
404 _token_start: &<I as Stream>::Checkpoint,
405 _kind: ErrorKind,
406 ) -> Self {
407 self
408 }
409}
410
411impl<I: Stream + Clone, C> AddContext<I, C> for InputError<I> {}
412
413#[cfg(feature = "unstable-recover")]
414#[cfg(feature = "std")]
415impl<I: Clone + Stream> FromRecoverableError<I, Self> for InputError<I> {
416 #[inline]
417 fn from_recoverable_error(
418 _token_start: &<I as Stream>::Checkpoint,
419 _err_start: &<I as Stream>::Checkpoint,
420 _input: &I,
421 e: Self,
422 ) -> Self {
423 e
424 }
425}
426
427impl<I: Clone, E> FromExternalError<I, E> for InputError<I> {
428 #[inline]
430 fn from_external_error(input: &I, kind: ErrorKind, _e: E) -> Self {
431 Self {
432 input: input.clone(),
433 kind,
434 }
435 }
436}
437
438impl<I: Clone> ErrorConvert<InputError<(I, usize)>> for InputError<I> {
439 #[inline]
440 fn convert(self) -> InputError<(I, usize)> {
441 InputError {
442 input: (self.input, 0),
443 kind: self.kind,
444 }
445 }
446}
447
448impl<I: Clone> ErrorConvert<InputError<I>> for InputError<(I, usize)> {
449 #[inline]
450 fn convert(self) -> InputError<I> {
451 InputError {
452 input: self.input.0,
453 kind: self.kind,
454 }
455 }
456}
457
458impl<I: Clone + fmt::Display> fmt::Display for InputError<I> {
460 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
461 write!(
462 f,
463 "{} error starting at: {}",
464 self.kind.description(),
465 self.input
466 )
467 }
468}
469
470#[cfg(feature = "std")]
471impl<I: Clone + fmt::Debug + fmt::Display + Sync + Send + 'static> std::error::Error
472 for InputError<I>
473{
474}
475
476impl<I: Stream> ParserError<I> for () {
477 #[inline]
478 fn from_error_kind(_: &I, _: ErrorKind) -> Self {}
479
480 #[inline]
481 fn append(
482 self,
483 _input: &I,
484 _token_start: &<I as Stream>::Checkpoint,
485 _kind: ErrorKind,
486 ) -> Self {
487 }
488}
489
490impl<I: Stream, C> AddContext<I, C> for () {}
491
492#[cfg(feature = "unstable-recover")]
493#[cfg(feature = "std")]
494impl<I: Stream> FromRecoverableError<I, Self> for () {
495 #[inline]
496 fn from_recoverable_error(
497 _token_start: &<I as Stream>::Checkpoint,
498 _err_start: &<I as Stream>::Checkpoint,
499 _input: &I,
500 (): Self,
501 ) -> Self {
502 }
503}
504
505impl<I, E> FromExternalError<I, E> for () {
506 #[inline]
507 fn from_external_error(_input: &I, _kind: ErrorKind, _e: E) -> Self {}
508}
509
510impl ErrorConvert<()> for () {
511 #[inline]
512 fn convert(self) {}
513}
514
515#[derive(Debug)]
517pub struct ContextError<C = StrContext> {
518 #[cfg(feature = "alloc")]
519 context: crate::lib::std::vec::Vec<C>,
520 #[cfg(not(feature = "alloc"))]
521 context: core::marker::PhantomData<C>,
522 #[cfg(feature = "std")]
523 cause: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
524}
525
526impl<C> ContextError<C> {
527 #[inline]
529 pub fn new() -> Self {
530 Self {
531 context: Default::default(),
532 #[cfg(feature = "std")]
533 cause: None,
534 }
535 }
536
537 #[inline]
539 #[cfg(feature = "alloc")]
540 pub fn context(&self) -> impl Iterator<Item = &C> {
541 self.context.iter()
542 }
543
544 #[inline]
546 #[cfg(feature = "std")]
547 pub fn cause(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> {
548 self.cause.as_deref()
549 }
550}
551
552impl<C: Clone> Clone for ContextError<C> {
553 fn clone(&self) -> Self {
554 Self {
555 context: self.context.clone(),
556 #[cfg(feature = "std")]
557 cause: self.cause.as_ref().map(|e| e.to_string().into()),
558 }
559 }
560}
561
562impl<C> Default for ContextError<C> {
563 #[inline]
564 fn default() -> Self {
565 Self::new()
566 }
567}
568
569impl<I: Stream, C> ParserError<I> for ContextError<C> {
570 #[inline]
571 fn from_error_kind(_input: &I, _kind: ErrorKind) -> Self {
572 Self::new()
573 }
574
575 #[inline]
576 fn append(
577 self,
578 _input: &I,
579 _token_start: &<I as Stream>::Checkpoint,
580 _kind: ErrorKind,
581 ) -> Self {
582 self
583 }
584
585 #[inline]
586 fn or(self, other: Self) -> Self {
587 other
588 }
589}
590
591impl<C, I: Stream> AddContext<I, C> for ContextError<C> {
592 #[inline]
593 fn add_context(
594 mut self,
595 _input: &I,
596 _token_start: &<I as Stream>::Checkpoint,
597 context: C,
598 ) -> Self {
599 #[cfg(feature = "alloc")]
600 self.context.push(context);
601 self
602 }
603}
604
605#[cfg(feature = "unstable-recover")]
606#[cfg(feature = "std")]
607impl<I: Stream, C> FromRecoverableError<I, Self> for ContextError<C> {
608 #[inline]
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
619#[cfg(feature = "std")]
620impl<C, I, E: std::error::Error + Send + Sync + 'static> FromExternalError<I, E>
621 for ContextError<C>
622{
623 #[inline]
624 fn from_external_error(_input: &I, _kind: ErrorKind, e: E) -> Self {
625 let mut err = Self::new();
626 {
627 err.cause = Some(Box::new(e));
628 }
629 err
630 }
631}
632
633#[cfg(not(feature = "std"))]
635impl<C, I, E: Send + Sync + 'static> FromExternalError<I, E> for ContextError<C> {
636 #[inline]
637 fn from_external_error(_input: &I, _kind: ErrorKind, _e: E) -> Self {
638 let err = Self::new();
639 err
640 }
641}
642
643impl<C: core::cmp::PartialEq> core::cmp::PartialEq for ContextError<C> {
645 fn eq(&self, other: &Self) -> bool {
646 #[cfg(feature = "alloc")]
647 {
648 if self.context != other.context {
649 return false;
650 }
651 }
652 #[cfg(feature = "std")]
653 {
654 if self.cause.as_ref().map(ToString::to_string)
655 != other.cause.as_ref().map(ToString::to_string)
656 {
657 return false;
658 }
659 }
660
661 true
662 }
663}
664
665impl crate::lib::std::fmt::Display for ContextError<StrContext> {
666 fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result {
667 #[cfg(feature = "alloc")]
668 {
669 let expression = self.context().find_map(|c| match c {
670 StrContext::Label(c) => Some(c),
671 _ => None,
672 });
673 let expected = self
674 .context()
675 .filter_map(|c| match c {
676 StrContext::Expected(c) => Some(c),
677 _ => None,
678 })
679 .collect::<crate::lib::std::vec::Vec<_>>();
680
681 let mut newline = false;
682
683 if let Some(expression) = expression {
684 newline = true;
685
686 write!(f, "invalid {expression}")?;
687 }
688
689 if !expected.is_empty() {
690 if newline {
691 writeln!(f)?;
692 }
693 newline = true;
694
695 write!(f, "expected ")?;
696 for (i, expected) in expected.iter().enumerate() {
697 if i != 0 {
698 write!(f, ", ")?;
699 }
700 write!(f, "{expected}")?;
701 }
702 }
703 #[cfg(feature = "std")]
704 {
705 if let Some(cause) = self.cause() {
706 if newline {
707 writeln!(f)?;
708 }
709 write!(f, "{cause}")?;
710 }
711 }
712 }
713
714 Ok(())
715 }
716}
717
718impl<C> ErrorConvert<ContextError<C>> for ContextError<C> {
719 #[inline]
720 fn convert(self) -> ContextError<C> {
721 self
722 }
723}
724
725#[derive(Clone, Debug, PartialEq, Eq)]
727#[non_exhaustive]
728pub enum StrContext {
729 Label(&'static str),
731 Expected(StrContextValue),
733}
734
735impl crate::lib::std::fmt::Display for StrContext {
736 fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result {
737 match self {
738 Self::Label(name) => write!(f, "invalid {name}"),
739 Self::Expected(value) => write!(f, "expected {value}"),
740 }
741 }
742}
743
744#[derive(Clone, Debug, PartialEq, Eq)]
746#[non_exhaustive]
747pub enum StrContextValue {
748 CharLiteral(char),
750 StringLiteral(&'static str),
752 Description(&'static str),
754}
755
756impl From<char> for StrContextValue {
757 #[inline]
758 fn from(inner: char) -> Self {
759 Self::CharLiteral(inner)
760 }
761}
762
763impl From<&'static str> for StrContextValue {
764 #[inline]
765 fn from(inner: &'static str) -> Self {
766 Self::StringLiteral(inner)
767 }
768}
769
770impl crate::lib::std::fmt::Display for StrContextValue {
771 fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result {
772 match self {
773 Self::CharLiteral('\n') => "newline".fmt(f),
774 Self::CharLiteral('`') => "'`'".fmt(f),
775 Self::CharLiteral(c) if c.is_ascii_control() => {
776 write!(f, "`{}`", c.escape_debug())
777 }
778 Self::CharLiteral(c) => write!(f, "`{c}`"),
779 Self::StringLiteral(c) => write!(f, "`{c}`"),
780 Self::Description(c) => write!(f, "{c}"),
781 }
782 }
783}
784
785#[derive(Debug)]
787#[cfg(feature = "std")]
788pub enum TreeError<I, C = StrContext> {
789 Base(TreeErrorBase<I>),
791 Stack {
793 base: Box<Self>,
795 stack: Vec<TreeErrorFrame<I, C>>,
797 },
798 Alt(Vec<Self>),
800}
801
802#[derive(Debug)]
804#[cfg(feature = "std")]
805pub enum TreeErrorFrame<I, C = StrContext> {
806 Kind(TreeErrorBase<I>),
808 Context(TreeErrorContext<I, C>),
810}
811
812#[derive(Debug)]
814#[cfg(feature = "std")]
815pub struct TreeErrorBase<I> {
816 pub input: I,
818 pub kind: ErrorKind,
820 pub cause: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
822}
823
824#[derive(Debug)]
826#[cfg(feature = "std")]
827pub struct TreeErrorContext<I, C = StrContext> {
828 pub input: I,
830 pub context: C,
832}
833
834#[cfg(feature = "std")]
835impl<'i, I: ToOwned, C> TreeError<&'i I, C>
836where
837 &'i I: Stream + Clone,
838 <I as ToOwned>::Owned: Clone,
839{
840 pub fn into_owned(self) -> TreeError<<I as ToOwned>::Owned, C> {
842 self.map_input(ToOwned::to_owned)
843 }
844}
845
846#[cfg(feature = "std")]
847impl<I, C> TreeError<I, C>
848where
849 I: Stream + Clone,
850{
851 pub fn map_input<I2: Clone, O: Clone + Fn(I) -> I2>(self, op: O) -> TreeError<I2, C> {
853 match self {
854 TreeError::Base(base) => TreeError::Base(TreeErrorBase {
855 input: op(base.input),
856 kind: base.kind,
857 cause: base.cause,
858 }),
859 TreeError::Stack { base, stack } => {
860 let base = Box::new(base.map_input(op.clone()));
861 let stack = stack
862 .into_iter()
863 .map(|frame| match frame {
864 TreeErrorFrame::Kind(kind) => TreeErrorFrame::Kind(TreeErrorBase {
865 input: op(kind.input),
866 kind: kind.kind,
867 cause: kind.cause,
868 }),
869 TreeErrorFrame::Context(context) => {
870 TreeErrorFrame::Context(TreeErrorContext {
871 input: op(context.input),
872 context: context.context,
873 })
874 }
875 })
876 .collect();
877 TreeError::Stack { base, stack }
878 }
879 TreeError::Alt(alt) => {
880 TreeError::Alt(alt.into_iter().map(|e| e.map_input(op.clone())).collect())
881 }
882 }
883 }
884
885 fn append_frame(self, frame: TreeErrorFrame<I, C>) -> Self {
886 match self {
887 TreeError::Stack { base, mut stack } => {
888 stack.push(frame);
889 TreeError::Stack { base, stack }
890 }
891 base => TreeError::Stack {
892 base: Box::new(base),
893 stack: vec![frame],
894 },
895 }
896 }
897}
898
899#[cfg(feature = "std")]
900impl<I, C> ParserError<I> for TreeError<I, C>
901where
902 I: Stream + Clone,
903{
904 fn from_error_kind(input: &I, kind: ErrorKind) -> Self {
905 TreeError::Base(TreeErrorBase {
906 input: input.clone(),
907 kind,
908 cause: None,
909 })
910 }
911
912 fn append(self, input: &I, token_start: &<I as Stream>::Checkpoint, kind: ErrorKind) -> Self {
913 let mut input = input.clone();
914 input.reset(token_start);
915 let frame = TreeErrorFrame::Kind(TreeErrorBase {
916 input,
917 kind,
918 cause: None,
919 });
920 self.append_frame(frame)
921 }
922
923 fn or(self, other: Self) -> Self {
924 match (self, other) {
925 (TreeError::Alt(mut first), TreeError::Alt(second)) => {
926 first.extend(second);
931 TreeError::Alt(first)
932 }
933 (TreeError::Alt(mut alt), new) | (new, TreeError::Alt(mut alt)) => {
934 alt.push(new);
935 TreeError::Alt(alt)
936 }
937 (first, second) => TreeError::Alt(vec![first, second]),
938 }
939 }
940}
941
942#[cfg(feature = "std")]
943impl<I, C> AddContext<I, C> for TreeError<I, C>
944where
945 I: Stream + Clone,
946{
947 fn add_context(self, input: &I, token_start: &<I as Stream>::Checkpoint, context: C) -> Self {
948 let mut input = input.clone();
949 input.reset(token_start);
950 let frame = TreeErrorFrame::Context(TreeErrorContext { input, context });
951 self.append_frame(frame)
952 }
953}
954
955#[cfg(feature = "std")]
956#[cfg(feature = "unstable-recover")]
957impl<I: Stream + Clone, C> FromRecoverableError<I, Self> for TreeError<I, C> {
958 #[inline]
959 fn from_recoverable_error(
960 _token_start: &<I as Stream>::Checkpoint,
961 _err_start: &<I as Stream>::Checkpoint,
962 _input: &I,
963 e: Self,
964 ) -> Self {
965 e
966 }
967}
968
969#[cfg(feature = "std")]
970impl<I, C, E: std::error::Error + Send + Sync + 'static> FromExternalError<I, E> for TreeError<I, C>
971where
972 I: Stream + Clone,
973{
974 fn from_external_error(input: &I, kind: ErrorKind, e: E) -> Self {
975 TreeError::Base(TreeErrorBase {
976 input: input.clone(),
977 kind,
978 cause: Some(Box::new(e)),
979 })
980 }
981}
982
983#[cfg(feature = "std")]
984impl<I, C> TreeError<I, C>
985where
986 I: Stream + Clone + crate::lib::std::fmt::Display,
987 C: fmt::Display,
988{
989 fn write(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result {
990 let child_indent = indent + 2;
991 match self {
992 TreeError::Base(base) => {
993 writeln!(f, "{:indent$}{base}", "")?;
994 }
995 TreeError::Stack { base, stack } => {
996 base.write(f, indent)?;
997 for (level, frame) in stack.iter().enumerate() {
998 match frame {
999 TreeErrorFrame::Kind(frame) => {
1000 writeln!(f, "{:child_indent$}{level}: {frame}", "")?;
1001 }
1002 TreeErrorFrame::Context(frame) => {
1003 writeln!(f, "{:child_indent$}{level}: {frame}", "")?;
1004 }
1005 }
1006 }
1007 }
1008 TreeError::Alt(alt) => {
1009 writeln!(f, "{:indent$}during one of:", "")?;
1010 for child in alt {
1011 child.write(f, child_indent)?;
1012 }
1013 }
1014 }
1015
1016 Ok(())
1017 }
1018}
1019
1020#[cfg(feature = "std")]
1021impl<I: Stream + Clone + fmt::Display> fmt::Display for TreeErrorBase<I> {
1022 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1023 if let Some(cause) = self.cause.as_ref() {
1024 write!(f, "caused by {cause}")?;
1025 } else {
1026 let kind = self.kind.description();
1027 write!(f, "in {kind}")?;
1028 }
1029 let input = abbreviate(self.input.to_string());
1030 write!(f, " at '{input}'")?;
1031 Ok(())
1032 }
1033}
1034
1035#[cfg(feature = "std")]
1036impl<I: Stream + Clone + fmt::Display, C: fmt::Display> fmt::Display for TreeErrorContext<I, C> {
1037 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1038 let context = &self.context;
1039 let input = abbreviate(self.input.to_string());
1040 write!(f, "{context} at '{input}'")?;
1041 Ok(())
1042 }
1043}
1044
1045#[cfg(feature = "std")]
1046impl<
1047 I: Stream + Clone + fmt::Debug + fmt::Display + Sync + Send + 'static,
1048 C: fmt::Display + fmt::Debug,
1049 > std::error::Error for TreeError<I, C>
1050{
1051}
1052
1053#[cfg(feature = "std")]
1054fn abbreviate(input: String) -> String {
1055 let mut abbrev = None;
1056
1057 if let Some((line, _)) = input.split_once('\n') {
1058 abbrev = Some(line);
1059 }
1060
1061 let max_len = 20;
1062 let current = abbrev.unwrap_or(&input);
1063 if max_len < current.len() {
1064 if let Some((index, _)) = current.char_indices().nth(max_len) {
1065 abbrev = Some(¤t[..index]);
1066 }
1067 }
1068
1069 if let Some(abbrev) = abbrev {
1070 format!("{abbrev}...")
1071 } else {
1072 input
1073 }
1074}
1075
1076#[cfg(feature = "std")]
1077impl<I: Stream + Clone + fmt::Display, C: fmt::Display> fmt::Display for TreeError<I, C> {
1078 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1079 self.write(f, 0)
1080 }
1081}
1082
1083#[rustfmt::skip]
1085#[derive(Debug,PartialEq,Eq,Hash,Clone,Copy)]
1086#[allow(missing_docs)]
1087pub enum ErrorKind {
1088 Assert,
1089 Token,
1090 Tag,
1091 Alt,
1092 Many,
1093 Eof,
1094 Slice,
1095 Complete,
1096 Not,
1097 Verify,
1098 Fail,
1099}
1100
1101impl ErrorKind {
1102 #[rustfmt::skip]
1103 pub fn description(&self) -> &str {
1105 match *self {
1106 ErrorKind::Assert => "assert",
1107 ErrorKind::Token => "token",
1108 ErrorKind::Tag => "tag",
1109 ErrorKind::Alt => "alternative",
1110 ErrorKind::Many => "many",
1111 ErrorKind::Eof => "end of file",
1112 ErrorKind::Slice => "slice",
1113 ErrorKind::Complete => "complete",
1114 ErrorKind::Not => "negation",
1115 ErrorKind::Verify => "predicate verification",
1116 ErrorKind::Fail => "fail",
1117 }
1118 }
1119}
1120
1121impl<I: Stream> ParserError<I> for ErrorKind {
1122 #[inline]
1123 fn from_error_kind(_input: &I, kind: ErrorKind) -> Self {
1124 kind
1125 }
1126
1127 #[inline]
1128 fn append(
1129 self,
1130 _input: &I,
1131 _token_start: &<I as Stream>::Checkpoint,
1132 _kind: ErrorKind,
1133 ) -> Self {
1134 self
1135 }
1136}
1137
1138impl<I: Stream, C> AddContext<I, C> for ErrorKind {}
1139
1140impl<I, E> FromExternalError<I, E> for ErrorKind {
1141 #[inline]
1143 fn from_external_error(_input: &I, kind: ErrorKind, _e: E) -> Self {
1144 kind
1145 }
1146}
1147
1148impl fmt::Display for ErrorKind {
1150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1151 write!(f, "error {self:?}")
1152 }
1153}
1154
1155#[cfg(feature = "std")]
1156impl std::error::Error for ErrorKind {}
1157
1158#[derive(Clone, Debug, PartialEq, Eq)]
1160pub struct ParseError<I, E> {
1161 input: I,
1162 offset: usize,
1163 inner: E,
1164}
1165
1166impl<I: Stream, E: ParserError<I>> ParseError<I, E> {
1167 pub(crate) fn new(mut input: I, start: I::Checkpoint, inner: E) -> Self {
1168 let offset = input.offset_from(&start);
1169 input.reset(&start);
1170 Self {
1171 input,
1172 offset,
1173 inner,
1174 }
1175 }
1176}
1177
1178impl<I, E> ParseError<I, E> {
1179 #[inline]
1181 pub fn input(&self) -> &I {
1182 &self.input
1183 }
1184
1185 #[inline]
1190 pub fn offset(&self) -> usize {
1191 self.offset
1192 }
1193
1194 #[inline]
1196 pub fn inner(&self) -> &E {
1197 &self.inner
1198 }
1199
1200 #[inline]
1202 pub fn into_inner(self) -> E {
1203 self.inner
1204 }
1205}
1206
1207impl<I, E> core::fmt::Display for ParseError<I, E>
1208where
1209 I: AsBStr,
1210 E: core::fmt::Display,
1211{
1212 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1213 let input = self.input.as_bstr();
1214 let span_start = self.offset;
1215 let span_end = span_start;
1216 #[cfg(feature = "std")]
1217 if input.contains(&b'\n') {
1218 let (line_idx, col_idx) = translate_position(input, span_start);
1219 let line_num = line_idx + 1;
1220 let col_num = col_idx + 1;
1221 let gutter = line_num.to_string().len();
1222 let content = input
1223 .split(|c| *c == b'\n')
1224 .nth(line_idx)
1225 .expect("valid line number");
1226
1227 writeln!(f, "parse error at line {line_num}, column {col_num}")?;
1228 for _ in 0..gutter {
1230 write!(f, " ")?;
1231 }
1232 writeln!(f, " |")?;
1233
1234 write!(f, "{line_num} | ")?;
1236 writeln!(f, "{}", String::from_utf8_lossy(content))?;
1237
1238 for _ in 0..gutter {
1240 write!(f, " ")?;
1241 }
1242 write!(f, " | ")?;
1243 for _ in 0..col_idx {
1244 write!(f, " ")?;
1245 }
1246 write!(f, "^")?;
1249 for _ in (span_start + 1)..(span_end.min(span_start + content.len())) {
1250 write!(f, "^")?;
1251 }
1252 writeln!(f)?;
1253 } else {
1254 let content = input;
1255 writeln!(f, "{}", String::from_utf8_lossy(content))?;
1256 for _ in 0..span_start {
1257 write!(f, " ")?;
1258 }
1259 write!(f, "^")?;
1262 for _ in (span_start + 1)..(span_end.min(span_start + content.len())) {
1263 write!(f, "^")?;
1264 }
1265 writeln!(f)?;
1266 }
1267 write!(f, "{}", self.inner)?;
1268
1269 Ok(())
1270 }
1271}
1272
1273#[cfg(feature = "std")]
1274fn translate_position(input: &[u8], index: usize) -> (usize, usize) {
1275 if input.is_empty() {
1276 return (0, index);
1277 }
1278
1279 let safe_index = index.min(input.len() - 1);
1280 let column_offset = index - safe_index;
1281 let index = safe_index;
1282
1283 let nl = input[0..index]
1284 .iter()
1285 .rev()
1286 .enumerate()
1287 .find(|(_, b)| **b == b'\n')
1288 .map(|(nl, _)| index - nl - 1);
1289 let line_start = match nl {
1290 Some(nl) => nl + 1,
1291 None => 0,
1292 };
1293 let line = input[0..line_start].iter().filter(|b| **b == b'\n').count();
1294
1295 let column = crate::lib::std::str::from_utf8(&input[line_start..=index])
1297 .map(|s| s.chars().count() - 1)
1298 .unwrap_or_else(|_| index - line_start);
1299 let column = column + column_offset;
1300
1301 (line, column)
1302}
1303
1304#[cfg(test)]
1305#[cfg(feature = "std")]
1306mod test_parse_error {
1307 use super::*;
1308
1309 #[test]
1310 fn single_line() {
1311 let mut input = "0xZ123";
1312 let start = input.checkpoint();
1313 let _ = input.next_token().unwrap();
1314 let _ = input.next_token().unwrap();
1315 let inner = InputError::new(input, ErrorKind::Slice);
1316 let error = ParseError::new(input, start, inner);
1317 let expected = "\
13180xZ123
1319 ^
1320slice error starting at: Z123";
1321 assert_eq!(error.to_string(), expected);
1322 }
1323}
1324
1325#[cfg(test)]
1326#[cfg(feature = "std")]
1327mod test_translate_position {
1328 use super::*;
1329
1330 #[test]
1331 fn empty() {
1332 let input = b"";
1333 let index = 0;
1334 let position = translate_position(&input[..], index);
1335 assert_eq!(position, (0, 0));
1336 }
1337
1338 #[test]
1339 fn start() {
1340 let input = b"Hello";
1341 let index = 0;
1342 let position = translate_position(&input[..], index);
1343 assert_eq!(position, (0, 0));
1344 }
1345
1346 #[test]
1347 fn end() {
1348 let input = b"Hello";
1349 let index = input.len() - 1;
1350 let position = translate_position(&input[..], index);
1351 assert_eq!(position, (0, input.len() - 1));
1352 }
1353
1354 #[test]
1355 fn after() {
1356 let input = b"Hello";
1357 let index = input.len();
1358 let position = translate_position(&input[..], index);
1359 assert_eq!(position, (0, input.len()));
1360 }
1361
1362 #[test]
1363 fn first_line() {
1364 let input = b"Hello\nWorld\n";
1365 let index = 2;
1366 let position = translate_position(&input[..], index);
1367 assert_eq!(position, (0, 2));
1368 }
1369
1370 #[test]
1371 fn end_of_line() {
1372 let input = b"Hello\nWorld\n";
1373 let index = 5;
1374 let position = translate_position(&input[..], index);
1375 assert_eq!(position, (0, 5));
1376 }
1377
1378 #[test]
1379 fn start_of_second_line() {
1380 let input = b"Hello\nWorld\n";
1381 let index = 6;
1382 let position = translate_position(&input[..], index);
1383 assert_eq!(position, (1, 0));
1384 }
1385
1386 #[test]
1387 fn second_line() {
1388 let input = b"Hello\nWorld\n";
1389 let index = 8;
1390 let position = translate_position(&input[..], index);
1391 assert_eq!(position, (1, 2));
1392 }
1393}
1394
1395#[cfg(test)]
1398macro_rules! error_position(
1399 ($input:expr, $code:expr) => ({
1400 $crate::error::ParserError::from_error_kind($input, $code)
1401 });
1402);
1403
1404#[cfg(test)]
1405macro_rules! error_node_position(
1406 ($input:expr, $code:expr, $next:expr) => ({
1407 let start = $input.checkpoint();
1408 $crate::error::ParserError::append($next, $input, &start, $code)
1409 });
1410);