1use super::*;
10use alloc::borrow::Cow;
11
12pub use label::LabelError;
13
14pub trait Error<'a, I: Input<'a>>:
77 Sized + LabelError<'a, I, DefaultExpected<'a, I::Token>>
78{
79 #[inline(always)]
81 fn merge(self, other: Self) -> Self {
82 #![allow(unused_variables)]
83 self
84 }
85}
86
87#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
101#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Default)]
102pub struct EmptyErr(());
103
104impl<'a, I: Input<'a>> Error<'a, I> for EmptyErr {}
105
106impl<'a, I: Input<'a>, L> LabelError<'a, I, L> for EmptyErr {
107 #[inline(always)]
108 fn expected_found<E: IntoIterator<Item = L>>(
109 _: E,
110 _: Option<MaybeRef<'a, I::Token>>,
111 _: I::Span,
112 ) -> Self {
113 EmptyErr(())
114 }
115}
116
117impl fmt::Display for EmptyErr {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 write!(f, "error")
120 }
121}
122
123#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
137#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
138pub struct Cheap<S = SimpleSpan<usize>> {
139 span: S,
140}
141
142impl<S> Cheap<S> {
143 pub fn new(span: S) -> Self {
145 Self { span }
146 }
147
148 pub fn span(&self) -> &S {
152 &self.span
153 }
154}
155
156impl<'a, I: Input<'a>> Error<'a, I> for Cheap<I::Span> {}
157
158impl<'a, I: Input<'a>, L> LabelError<'a, I, L> for Cheap<I::Span> {
159 #[inline]
160 fn expected_found<E: IntoIterator<Item = L>>(
161 _expected: E,
162 _found: Option<MaybeRef<'a, I::Token>>,
163 span: I::Span,
164 ) -> Self {
165 Self { span }
166 }
167}
168
169impl<S> fmt::Debug for Cheap<S>
170where
171 S: fmt::Debug,
172{
173 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174 write!(f, "at {:?}", self.span)?;
175 Ok(())
176 }
177}
178
179impl<S> fmt::Display for Cheap<S>
180where
181 S: fmt::Debug,
182{
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 fmt::Debug::fmt(self, f)
185 }
186}
187
188#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
203#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
204pub struct Simple<'a, T, S = SimpleSpan<usize>> {
205 span: S,
206 found: Option<MaybeRef<'a, T>>,
207}
208
209impl<T, S> Simple<'_, T, S> {
210 pub fn span(&self) -> &S {
214 &self.span
215 }
216
217 pub fn found(&self) -> Option<&T> {
219 self.found.as_deref()
220 }
221}
222
223impl<'a, T, S> Simple<'a, T, S> {
224 pub fn new(found: Option<MaybeRef<'a, T>>, span: S) -> Self {
226 Self { span, found }
227 }
228
229 pub fn map_token<U, F: FnOnce(T) -> U>(self, f: F) -> Simple<'a, U, S>
234 where
235 T: Clone,
236 {
237 Simple {
238 span: self.span,
239 found: self.found.map(|found| f(found.into_inner()).into()),
240 }
241 }
242
243 pub fn map_span<S2, F: FnOnce(S) -> S2>(self, f: F) -> Simple<'a, T, S2> {
248 Simple {
249 span: f(self.span),
250 found: self.found,
251 }
252 }
253}
254
255impl<'a, I: Input<'a>> Error<'a, I> for Simple<'a, I::Token, I::Span> {}
256
257impl<'a, I: Input<'a>, L> LabelError<'a, I, L> for Simple<'a, I::Token, I::Span> {
258 #[inline]
259 fn expected_found<E: IntoIterator<Item = L>>(
260 _expected: E,
261 found: Option<MaybeRef<'a, I::Token>>,
262 span: I::Span,
263 ) -> Self {
264 Self { span, found }
265 }
266}
267
268impl<T, S> fmt::Debug for Simple<'_, T, S>
269where
270 T: fmt::Debug,
271 S: fmt::Debug,
272{
273 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
274 write!(f, "found ")?;
275 write_token(f, T::fmt, self.found.as_deref())?;
276 write!(f, " at {:?}", self.span)?;
277 Ok(())
278 }
279}
280
281impl<T, S> fmt::Display for Simple<'_, T, S>
282where
283 T: fmt::Debug,
284 S: fmt::Debug,
285{
286 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287 fmt::Debug::fmt(self, f)
288 }
289}
290
291#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
293#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
294#[non_exhaustive]
295pub enum RichPattern<'a, T> {
296 Token(MaybeRef<'a, T>),
298 Label(Cow<'a, str>),
300 Identifier(String),
302 Any,
304 SomethingElse,
306 EndOfInput,
308}
309
310impl<'a, T> TryFrom<DefaultExpected<'a, T>> for RichPattern<'a, T> {
311 type Error = ();
312 fn try_from(expected: DefaultExpected<'a, T>) -> Result<Self, ()> {
313 Ok(match expected {
314 DefaultExpected::Token(tok) => RichPattern::Token(tok),
315 DefaultExpected::Any => RichPattern::Any,
316 DefaultExpected::SomethingElse => RichPattern::SomethingElse,
317 DefaultExpected::EndOfInput => RichPattern::EndOfInput,
318 DefaultExpected::NothingElse => return Err(()),
319 })
320 }
321}
322
323impl<'a, Slice: core::fmt::Debug, T> TryFrom<text::TextExpected<Slice>> for RichPattern<'a, T> {
324 type Error = ();
325 fn try_from(expected: text::TextExpected<Slice>) -> Result<Self, ()> {
326 Ok(match expected {
327 text::TextExpected::Whitespace => RichPattern::Label(Cow::Borrowed("whitespace")),
328 text::TextExpected::InlineWhitespace => {
329 RichPattern::Label(Cow::Borrowed("inline whitespace"))
330 }
331 text::TextExpected::Newline => RichPattern::Label(Cow::Borrowed("newline")),
332 text::TextExpected::Digit(start, _end) if start > 0 => {
333 RichPattern::Label(Cow::Borrowed("non-zero digit"))
334 }
335 text::TextExpected::Digit(_, _) => RichPattern::Label(Cow::Borrowed("digit")),
336 text::TextExpected::AnyIdentifier => RichPattern::Label(Cow::Borrowed("identifier")),
337 text::TextExpected::Identifier(i) => RichPattern::Identifier(alloc::format!("{i:?}")),
338 text::TextExpected::Int => RichPattern::Label(Cow::Borrowed("int")),
339 })
340 }
341}
342
343impl<'a, T> TryFrom<MaybeRef<'a, T>> for RichPattern<'a, T> {
344 type Error = ();
345 fn try_from(tok: MaybeRef<'a, T>) -> Result<Self, ()> {
346 Ok(RichPattern::Token(tok))
347 }
348}
349
350impl<T> TryFrom<&'static str> for RichPattern<'_, T> {
351 type Error = ();
352 fn try_from(label: &'static str) -> Result<Self, ()> {
353 Ok(RichPattern::Label(Cow::Borrowed(label)))
354 }
355}
356
357impl<T> TryFrom<String> for RichPattern<'_, T> {
358 type Error = ();
359 fn try_from(label: String) -> Result<Self, ()> {
360 Ok(RichPattern::Label(Cow::Owned(label)))
361 }
362}
363
364impl TryFrom<char> for RichPattern<'_, char> {
365 type Error = ();
366 fn try_from(c: char) -> Result<Self, ()> {
367 Ok(Self::Token(MaybeRef::Val(c)))
368 }
369}
370
371impl<'a, T> RichPattern<'a, T> {
372 pub fn map_token<U, F: FnMut(T) -> U>(self, mut f: F) -> RichPattern<'a, U>
377 where
378 T: Clone,
379 {
380 match self {
381 Self::Token(t) => RichPattern::Token(f(t.into_inner()).into()),
382 Self::Label(l) => RichPattern::Label(l),
383 Self::Identifier(i) => RichPattern::Identifier(i),
384 Self::Any => RichPattern::Any,
385 Self::SomethingElse => RichPattern::SomethingElse,
386 Self::EndOfInput => RichPattern::EndOfInput,
387 }
388 }
389
390 pub fn into_owned<'b>(self) -> RichPattern<'b, T>
392 where
393 T: Clone,
394 {
395 match self {
396 Self::Token(tok) => RichPattern::Token(tok.into_owned()),
397 Self::Label(l) => RichPattern::Label(Cow::Owned(l.into_owned())),
398 Self::Identifier(i) => RichPattern::Identifier(i),
399 Self::Any => RichPattern::Any,
400 Self::SomethingElse => RichPattern::SomethingElse,
401 Self::EndOfInput => RichPattern::EndOfInput,
402 }
403 }
404
405 fn write(
406 &self,
407 f: &mut fmt::Formatter,
408 mut fmt_token: impl FnMut(&T, &mut fmt::Formatter<'_>) -> fmt::Result,
409 ) -> fmt::Result {
410 match self {
411 Self::Token(tok) => {
412 write!(f, "'")?;
413 fmt_token(tok, f)?;
414 write!(f, "'")
415 }
416 Self::Label(l) => write!(f, "{l}"),
417 Self::Identifier(i) => write!(f, "'{i}'"),
418 Self::Any => write!(f, "any"),
419 Self::SomethingElse => write!(f, "something else"),
420 Self::EndOfInput => write!(f, "end of input"),
421 }
422 }
423}
424
425impl<T> fmt::Debug for RichPattern<'_, T>
426where
427 T: fmt::Debug,
428{
429 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
430 self.write(f, |t, f| write!(f, "{t:?}"))
431 }
432}
433
434impl<T> fmt::Display for RichPattern<'_, T>
435where
436 T: fmt::Display,
437{
438 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
439 self.write(f, |t, f| write!(f, "{t}"))
440 }
441}
442
443#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
445#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
446pub enum RichReason<'a, T, C = String> {
447 ExpectedFound {
449 expected: Vec<RichPattern<'a, T>>,
451 found: Option<MaybeRef<'a, T>>,
453 },
454 Custom(C),
456}
457
458impl<'a, T, C> RichReason<'a, T, C> {
459 pub fn found(&self) -> Option<&T> {
461 match self {
462 Self::ExpectedFound { found, .. } => found.as_deref(),
463 Self::Custom(_) => None,
464 }
465 }
466
467 pub fn into_owned<'b>(self) -> RichReason<'b, T, C>
469 where
470 T: Clone,
471 {
472 match self {
473 Self::ExpectedFound { found, expected } => RichReason::ExpectedFound {
474 expected: expected.into_iter().map(RichPattern::into_owned).collect(),
475 found: found.map(MaybeRef::into_owned),
476 },
477 Self::Custom(msg) => RichReason::Custom(msg),
478 }
479 }
480
481 fn take_found(&mut self) -> Option<MaybeRef<'a, T>> {
482 match self {
483 RichReason::ExpectedFound { found, .. } => found.take(),
484 RichReason::Custom(_) => None,
485 }
486 }
487
488 pub fn map_token<U, F: FnMut(T) -> U>(self, mut f: F) -> RichReason<'a, U, C>
493 where
494 T: Clone,
495 {
496 match self {
497 RichReason::ExpectedFound { expected, found } => RichReason::ExpectedFound {
498 expected: expected
499 .into_iter()
500 .map(|pat| pat.map_token(&mut f))
501 .collect(),
502 found: found.map(|found| f(found.into_inner()).into()),
503 },
504 RichReason::Custom(msg) => RichReason::Custom(msg),
505 }
506 }
507}
508
509impl<'a, T, C> RichReason<'a, T, C>
510where
511 C: fmt::Display,
512{
513 fn inner_fmt<S>(
514 &self,
515 f: &mut fmt::Formatter<'_>,
516 mut fmt_token: impl FnMut(&T, &mut fmt::Formatter<'_>) -> fmt::Result,
517 mut fmt_span: impl FnMut(&S, &mut fmt::Formatter<'_>) -> fmt::Result,
518 span: Option<&S>,
519 context: &[(RichPattern<'a, T>, S)],
520 ) -> fmt::Result {
521 match self {
522 RichReason::ExpectedFound { expected, found } => {
523 write!(f, "found ")?;
524 write_token(f, &mut fmt_token, found.as_deref())?;
525 if let Some(span) = span {
526 write!(f, " at ")?;
527 fmt_span(span, f)?;
528 }
529 write!(f, " expected ")?;
530 match &expected[..] {
531 [] => write!(f, "something else")?,
532 [expected] => expected.write(f, &mut fmt_token)?,
533 _ => {
534 for expected in &expected[..expected.len() - 1] {
535 expected.write(f, &mut fmt_token)?;
536 write!(f, ", ")?;
537 }
538 write!(f, "or ")?;
539 expected.last().unwrap().write(f, &mut fmt_token)?;
540 }
541 }
542 }
543 RichReason::Custom(msg) => {
544 write!(f, "{msg}")?;
545 if let Some(span) = span {
546 write!(f, " at ")?;
547 fmt_span(span, f)?;
548 }
549 }
550 }
551 for (l, s) in context {
552 write!(f, " in ")?;
553 l.write(f, &mut fmt_token)?;
554 write!(f, " at ")?;
555 fmt_span(s, f)?;
556 }
557 Ok(())
558 }
559}
560
561impl<T, C> RichReason<'_, T, C>
562where
563 T: PartialEq,
564{
565 #[inline]
566 fn flat_merge(self, other: Self) -> Self {
567 match (self, other) {
568 (a @ RichReason::Custom(_), _) => a,
570 (_, b @ RichReason::Custom(_)) => b,
571 (
572 RichReason::ExpectedFound {
573 expected: mut this_expected,
574 found,
575 },
576 RichReason::ExpectedFound {
577 expected: mut other_expected,
578 ..
579 },
580 ) => {
581 if other_expected.len() > this_expected.len() {
583 core::mem::swap(&mut this_expected, &mut other_expected);
584 }
585 for expected in other_expected {
586 if !this_expected[..].contains(&expected) {
587 this_expected.push(expected);
588 }
589 }
590 RichReason::ExpectedFound {
591 expected: this_expected,
592 found,
593 }
594 }
595 }
596 }
597}
598
599impl<T, C> fmt::Display for RichReason<'_, T, C>
600where
601 T: fmt::Display,
602 C: fmt::Display,
603{
604 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
605 self.inner_fmt(f, T::fmt, |_: &(), _| Ok(()), None, &[])
606 }
607}
608
609#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
631pub struct Rich<'a, T, S = SimpleSpan<usize>, C = String> {
632 span: S,
633 reason: Box<RichReason<'a, T, C>>,
634 context: Vec<(RichPattern<'a, T>, S)>,
635}
636
637impl<T, S, C> Rich<'_, T, S, C>
638where
639 C: fmt::Display,
640{
641 fn inner_fmt(
642 &self,
643 f: &mut fmt::Formatter<'_>,
644 fmt_token: impl FnMut(&T, &mut fmt::Formatter<'_>) -> fmt::Result,
645 fmt_span: impl FnMut(&S, &mut fmt::Formatter<'_>) -> fmt::Result,
646 with_spans: bool,
647 ) -> fmt::Result {
648 self.reason.inner_fmt(
649 f,
650 fmt_token,
651 fmt_span,
652 if with_spans { Some(&self.span) } else { None },
653 &self.context,
654 )
655 }
656}
657
658impl<'a, T, S, C> Rich<'a, T, S, C> {
659 #[inline]
661 pub fn custom<M: Into<C>>(span: S, msg: M) -> Self {
662 Rich {
663 span,
664 reason: Box::new(RichReason::Custom(msg.into())),
665 context: Vec::new(),
666 }
667 }
668
669 pub fn span(&self) -> &S {
673 &self.span
674 }
675
676 pub fn reason(&self) -> &RichReason<'a, T, C> {
678 &self.reason
679 }
680
681 pub fn into_reason(self) -> RichReason<'a, T, C> {
683 *self.reason
684 }
685
686 pub fn found(&self) -> Option<&T> {
688 self.reason.found()
689 }
690
691 pub fn contexts(&self) -> impl Iterator<Item = (&RichPattern<'a, T>, &S)> {
696 self.context.iter().map(|(l, s)| (l, s))
697 }
698
699 pub fn into_owned<'b>(self) -> Rich<'b, T, S, C>
701 where
702 T: Clone,
703 {
704 Rich {
705 reason: Box::new(self.reason.into_owned()),
706 context: self
707 .context
708 .into_iter()
709 .map(|(p, s)| (p.into_owned(), s))
710 .collect(),
711 ..self
712 }
713 }
714
715 pub fn expected(&self) -> impl ExactSizeIterator<Item = &RichPattern<'a, T>> {
717 match &*self.reason {
718 RichReason::ExpectedFound { expected, .. } => expected.iter(),
719 RichReason::Custom(_) => [].iter(),
720 }
721 }
722
723 pub fn map_token<U, F: FnMut(T) -> U>(self, mut f: F) -> Rich<'a, U, S, C>
728 where
729 T: Clone,
730 {
731 Rich {
732 span: self.span,
733 reason: Box::new(self.reason.map_token(&mut f)),
734 context: self
735 .context
736 .into_iter()
737 .map(|(p, s)| (p.map_token(&mut f), s))
738 .collect(),
739 }
740 }
741
742 pub fn map_span<S2, F: FnMut(S) -> S2>(self, mut f: F) -> Rich<'a, T, S2, C> {
747 Rich {
748 span: f(self.span),
749 reason: self.reason,
750 context: self.context.into_iter().map(|(p, s)| (p, f(s))).collect(),
751 }
752 }
753}
754
755impl<'a, I: Input<'a>, C> Error<'a, I> for Rich<'a, I::Token, I::Span, C>
756where
757 I::Token: PartialEq,
758{
759 #[inline]
760 fn merge(self, other: Self) -> Self {
761 let new_reason = self.reason.flat_merge(*other.reason);
762 Self {
763 span: self.span,
764 reason: Box::new(new_reason),
765 context: self.context, }
767 }
768}
769
770impl<'a, I: Input<'a>, L, C> LabelError<'a, I, L> for Rich<'a, I::Token, I::Span, C>
771where
772 I::Token: PartialEq,
773 L: TryInto<RichPattern<'a, I::Token>>,
774{
775 #[inline]
776 fn expected_found<E: IntoIterator<Item = L>>(
777 expected: E,
778 found: Option<MaybeRef<'a, I::Token>>,
779 span: I::Span,
780 ) -> Self {
781 Self {
782 span,
783 reason: Box::new(RichReason::ExpectedFound {
784 expected: expected
785 .into_iter()
786 .filter_map(|tok| tok.try_into().ok())
787 .collect(),
788 found,
789 }),
790 context: Vec::new(),
791 }
792 }
793
794 #[inline]
795 fn merge_expected_found<E: IntoIterator<Item = L>>(
796 mut self,
797 new_expected: E,
798 new_found: Option<MaybeRef<'a, I::Token>>,
799 _span: I::Span,
800 ) -> Self {
801 match &mut *self.reason {
802 RichReason::ExpectedFound { expected, found } => {
803 for new_expected in new_expected {
804 if let Ok(new_expected) = new_expected.try_into() {
805 if !expected[..].contains(&new_expected) {
806 expected.push(new_expected);
807 }
808 }
809 }
810 *found = found.take().or(new_found); }
812 RichReason::Custom(_) => {}
813 }
814 self
816 }
817
818 #[inline]
819 fn replace_expected_found<E: IntoIterator<Item = L>>(
820 mut self,
821 new_expected: E,
822 new_found: Option<MaybeRef<'a, I::Token>>,
823 span: I::Span,
824 ) -> Self {
825 self.span = span;
826 match &mut *self.reason {
827 RichReason::ExpectedFound { expected, found } => {
828 expected.clear();
829 expected.extend(
830 new_expected
831 .into_iter()
832 .filter_map(|tok| tok.try_into().ok()),
833 );
834 *found = new_found;
835 }
836 _ => {
837 *self.reason = RichReason::ExpectedFound {
838 expected: new_expected
839 .into_iter()
840 .filter_map(|tok| tok.try_into().ok())
841 .collect(),
842 found: new_found,
843 };
844 }
845 }
846 self.context.clear();
847 self
848 }
849
850 #[inline]
851 fn label_with(&mut self, label: L) {
852 match &mut *self.reason {
854 RichReason::ExpectedFound { expected, found: _ } => {
855 expected.clear();
856 expected.extend(label.try_into().ok());
857 }
858 _ => {
859 *self.reason = RichReason::ExpectedFound {
860 expected: label.try_into().ok().into_iter().collect(),
861 found: self.reason.take_found(),
862 };
863 }
864 }
865 }
866
867 #[inline]
868 fn in_context(&mut self, label: L, span: I::Span) {
869 if let Ok(label) = label.try_into() {
870 if self.context.iter().all(|(l, _)| l != &label) {
871 self.context.push((label, span));
872 }
873 }
874 }
875}
876
877impl<T, S, C> fmt::Debug for Rich<'_, T, S, C>
878where
879 T: fmt::Debug,
880 S: fmt::Debug,
881 C: fmt::Display,
882{
883 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
884 self.inner_fmt(f, T::fmt, S::fmt, true)
885 }
886}
887
888impl<T, S, C> fmt::Display for Rich<'_, T, S, C>
889where
890 T: fmt::Display,
891 S: fmt::Display,
892 C: fmt::Display,
893{
894 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
895 self.inner_fmt(f, T::fmt, S::fmt, false)
896 }
897}
898
899fn write_token<T>(
900 f: &mut fmt::Formatter,
901 mut fmt_token: impl FnMut(&T, &mut fmt::Formatter<'_>) -> fmt::Result,
902 tok: Option<&T>,
903) -> fmt::Result {
904 match tok {
905 Some(tok) => {
906 write!(f, "'")?;
907 fmt_token(tok, f)?;
908 write!(f, "'")
909 }
910 None => write!(f, "end of input"),
911 }
912}