1use alloc::{string::String, string::ToString, vec::Vec};
4use core::fmt::{self, Display};
5
6#[derive(Clone, Debug)]
11pub struct Exn<'a, V>(pub(crate) Inner<'a, V>);
12
13#[derive(Clone, Debug)]
14pub(crate) enum Inner<'a, V> {
15 Err(Error<V>),
16 TailCall(&'a crate::compile::TermId, crate::filter::Vars<'a, V>, V),
21 Break(usize),
22}
23
24impl<V> Exn<'_, V> {
25 pub(crate) fn get_err(self) -> Result<Error<V>, Self> {
27 match self.0 {
28 Inner::Err(e) => Ok(e),
29 _ => Err(self),
30 }
31 }
32}
33
34impl<V> From<Error<V>> for Exn<'_, V> {
35 fn from(e: Error<V>) -> Self {
36 Exn(Inner::Err(e))
37 }
38}
39
40#[derive(Clone, Debug, PartialEq, Eq)]
41enum Part<V, S = &'static str> {
42 Val(V),
43 Str(S),
44}
45
46#[derive(Clone, Debug, PartialEq, Eq)]
48pub struct Error<V>(Part<V, Vec<Part<V>>>);
49
50impl<V> Error<V> {
51 pub fn new(v: V) -> Self {
53 Self(Part::Val(v))
54 }
55
56 pub fn path_expr() -> Self {
58 Self(Part::Str(Vec::from([Part::Str("invalid path expression")])))
59 }
60
61 pub fn typ(v: V, typ: &'static str) -> Self {
63 use Part::{Str, Val};
64 [Str("cannot use "), Val(v), Str(" as "), Str(typ)]
65 .into_iter()
66 .collect()
67 }
68
69 pub fn math(l: V, op: crate::ops::Math, r: V) -> Self {
71 use Part::{Str, Val};
72 [
73 Str("cannot calculate "),
74 Val(l),
75 Str(" "),
76 Str(op.as_str()),
77 Str(" "),
78 Val(r),
79 ]
80 .into_iter()
81 .collect()
82 }
83
84 pub fn index(l: V, r: V) -> Self {
86 use Part::{Str, Val};
87 [Str("cannot index "), Val(l), Str(" with "), Val(r)]
88 .into_iter()
89 .collect()
90 }
91}
92
93impl<V: From<String>> Error<V> {
94 pub fn str(s: impl ToString) -> Self {
96 Self(Part::Val(V::from(s.to_string())))
97 }
98}
99
100impl<V> FromIterator<Part<V>> for Error<V> {
101 fn from_iter<T: IntoIterator<Item = Part<V>>>(iter: T) -> Self {
102 Self(Part::Str(iter.into_iter().collect()))
103 }
104}
105
106impl<V: From<String> + Display> Error<V> {
107 pub fn into_val(self) -> V {
109 if let Part::Val(v) = self.0 {
110 v
111 } else {
112 V::from(self.to_string())
113 }
114 }
115}
116
117impl<V: Display> Display for Error<V> {
118 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119 match &self.0 {
120 Part::Val(v) => v.fmt(f),
121 Part::Str(parts) => parts.iter().try_for_each(|part| match part {
122 Part::Val(v) => v.fmt(f),
123 Part::Str(s) => s.fmt(f),
124 }),
125 }
126 }
127}